From 5c820c0ceaa9e915ae3233ed334444a66ab94315 Mon Sep 17 00:00:00 2001 From: Joanna Dyczka Date: Wed, 20 Mar 2024 09:53:43 +0100 Subject: [PATCH 1/2] [#541] move individual dashboard cards into separate components --- .../components/organisms/DashboardCards.tsx | 501 ++---------------- .../DashboardCards/DRepDashboardCard.tsx | 144 +++++ .../DashboardCards/DelegateDashboardCard.tsx | 207 ++++++++ .../ListGovActionsDashboardCard.tsx | 30 ++ .../ProposeGovActionDashboardCard.tsx | 49 ++ .../DashboardCards/SoleVoterDashboardCard.tsx | 117 ++++ 6 files changed, 590 insertions(+), 458 deletions(-) create mode 100644 govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx create mode 100644 govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx create mode 100644 govtool/frontend/src/components/organisms/DashboardCards/ListGovActionsDashboardCard.tsx create mode 100644 govtool/frontend/src/components/organisms/DashboardCards/ProposeGovActionDashboardCard.tsx create mode 100644 govtool/frontend/src/components/organisms/DashboardCards/SoleVoterDashboardCard.tsx diff --git a/govtool/frontend/src/components/organisms/DashboardCards.tsx b/govtool/frontend/src/components/organisms/DashboardCards.tsx index 98a99630d..051c70b91 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards.tsx @@ -1,19 +1,16 @@ -import { useCallback, useMemo } from "react"; -import { useNavigate } from "react-router-dom"; import { Box, CircularProgress } from "@mui/material"; -import { Trans } from "react-i18next"; - -import { IMAGES, PATHS } from "@consts"; import { useCardano } from "@context"; import { useGetAdaHolderVotingPowerQuery, useScreenDimension, useGetAdaHolderCurrentDelegationQuery, - useTranslation, useGetVoterInfo, } from "@hooks"; -import { DashboardActionCard } from "@molecules"; -import { correctAdaFormat, formHexToBech32, openInNewTab } from "@utils"; +import { DelegateDashboardCard } from "./DashboardCards/DelegateDashboardCard"; +import { DRepDashboardCard } from "./DashboardCards/DRepDashboardCard"; +import { SoleVoterDashboardCard } from "./DashboardCards/SoleVoterDashboardCard"; +import { ListGovActionsDashboardCards } from "./DashboardCards/ListGovActionsDashboardCard"; +import { ProposeGovActionDashboardCard } from "./DashboardCards/ProposeGovActionDashboardCard"; export const DashboardCards = () => { const { @@ -23,246 +20,29 @@ export const DashboardCards = () => { pendingTransaction, stakeKey, } = useCardano(); - const navigate = useNavigate(); - const { currentDelegation } = useGetAdaHolderCurrentDelegationQuery(stakeKey); const { screenWidth } = useScreenDimension(); + + const { currentDelegation } = useGetAdaHolderCurrentDelegationQuery(stakeKey); const { votingPower } = useGetAdaHolderVotingPowerQuery(stakeKey); - const { t } = useTranslation(); const { voter } = useGetVoterInfo(); - const delegationDescription = useMemo(() => { - const correctAdaRepresentation = correctAdaFormat(votingPower); - if (currentDelegation === dRepID) { - return ( - - ); - } - if (currentDelegation === "drep_always_no_confidence") { - return ( - - ); - } - if (currentDelegation === "drep_always_abstain") { - return ( - - ); - } - if (currentDelegation) { - return ( - - ); - } + if (!currentDelegation || !voter || !votingPower) { return ( - + + + ); - }, [currentDelegation, dRepID, votingPower]); - - const delegationStatusTestForId = useMemo(() => { - if (currentDelegation === dRepID) { - return "myself"; - } - if (currentDelegation === "drep_always_no_confidence") { - return "no-confidence"; - } - if (currentDelegation === "drep_always_abstain") { - return "abstain"; - } - if (currentDelegation) { - return "dRep"; - } - return "not_delegated"; - }, [currentDelegation, dRepID, votingPower]); - - const progressDescription = useMemo(() => { - const correctAdaRepresentation = correctAdaFormat(votingPower); - if (!pendingTransaction.delegate) return; - const { resourceId } = pendingTransaction.delegate; - - if (resourceId === dRepID) { - return ( - - ); - } - if (resourceId === "no confidence") { - return ( - - ); - } - if (resourceId === "abstain") { - return ( - - ); - } - if (resourceId) { - return ( - - ); - } - }, [pendingTransaction, dRepID, votingPower]); - - const navigateTo = useCallback( - (path: string) => { - const isPendingTx = isPendingTransaction(); - if (isPendingTx) return; - navigate(path); - }, - [isPendingTransaction, navigate], - ); - - const onClickGovernanceActionCardActionButton = useCallback(() => { - if (pendingTransaction.createGovAction) { - navigate(PATHS.dashboardGovernanceActions); - return; - } - navigate(PATHS.createGovernanceAction); - }, [pendingTransaction.createGovAction, navigate]); - - const displayedDelegationId = useMemo(() => { - const restrictedNames = [ - dRepID, - "drep_always_abstain", - "drep_always_no_confidence", - "abstain", - "no confidence", - ]; - if (pendingTransaction.delegate) { - const delegateTo = pendingTransaction.delegate.resourceId; - if (!restrictedNames.includes(delegateTo)) { - return delegateTo.includes("drep") - ? delegateTo - : formHexToBech32(delegateTo); - } - return undefined; - } - if (!restrictedNames.includes(currentDelegation)) { - return formHexToBech32(currentDelegation); - } - return undefined; - }, [currentDelegation, dRepID, pendingTransaction, formHexToBech32]); - - const registrationCardDescription = useMemo(() => { - if (pendingTransaction.registerAsDrep) - return t("dashboard.registration.registrationInProgress"); - - if (pendingTransaction.retireAsDrep) - return t("dashboard.registration.retirementInProgress"); - - if (pendingTransaction.updateMetaData) - return t("dashboard.registration.metadataUpdateInProgress"); - - if (voter?.isRegisteredAsDRep || voter?.wasRegisteredAsDRep) - return t("dashboard.registration.holdersCanDelegate"); - - return t("dashboard.registration.ifYouWant"); - }, [ - pendingTransaction, - voter?.isRegisteredAsDRep, - voter?.wasRegisteredAsDRep, - ]); - - const soleVoterCardDescription = useMemo(() => { - if (pendingTransaction.registerAsSoleVoter) - return "dashboard.soleVoter.registrationInProgress"; - - if (pendingTransaction.retireAsSoleVoter) - return "dashboard.soleVoter.retirementInProgress"; - - if (voter?.isRegisteredAsSoleVoter) - return "dashboard.soleVoter.isRegisteredDescription"; - - if (voter?.wasRegisteredAsSoleVoter) - return "dashboard.soleVoter.wasRegisteredDescription"; - - return "dashboard.soleVoter.registerDescription"; - }, [ - pendingTransaction, - voter?.isRegisteredAsSoleVoter, - voter?.wasRegisteredAsSoleVoter, - ]); + } - const registrationCardTitle = useMemo(() => { - if (pendingTransaction.retireAsDrep) - return t("dashboard.registration.dRepRetirement"); - - if (pendingTransaction.registerAsDrep) - return t("dashboard.registration.dRepRegistration"); - - if (pendingTransaction.updateMetaData) - return t("dashboard.registration.dRepUpdate"); - - if (voter?.isRegisteredAsDRep) - return t("dashboard.registration.youAreRegistered"); - - if (voter?.wasRegisteredAsDRep) - return t("dashboard.registration.registerAgain"); - - return t("dashboard.registration.registerAsDRep"); - }, [ - pendingTransaction, - voter?.isRegisteredAsDRep, - voter?.wasRegisteredAsDRep, - ]); - - const soleVoterCardTitle = useMemo(() => { - if (pendingTransaction.retireAsSoleVoter) - return t("dashboard.soleVoter.retirement"); - - if (pendingTransaction.registerAsSoleVoter) - return t("dashboard.soleVoter.registration"); - - if (voter?.isRegisteredAsSoleVoter) - return t("dashboard.soleVoter.youAreSoleVoterTitle"); - - if (voter?.wasRegisteredAsSoleVoter) - return t("dashboard.soleVoter.wasSoleVoterTitle"); - - return t("dashboard.soleVoter.registerTitle"); - }, [ - pendingTransaction, - voter?.isRegisteredAsSoleVoter, - voter?.isRegisteredAsSoleVoter, - ]); - - return !voter || !votingPower ? ( - - - - ) : ( + return ( { rowGap: 3, }} > - {/* DELEGATION CARD */} - navigateTo(PATHS.delegateTodRep)} - firstButtonLabel={ - pendingTransaction.delegate - ? "" - : currentDelegation - ? t("dashboard.delegation.changeDelegation") - : t("delegate") - } - firstButtonVariant={currentDelegation ? "outlined" : "contained"} - imageURL={IMAGES.govActionDelegateImage} - cardId={displayedDelegationId} - inProgress={!!pendingTransaction.delegate} - cardTitle={t("dashboard.delegation.dRepDelegatedTo")} - secondButtonAction={ - pendingTransaction.delegate - ? () => openInNewTab("https://adanordic.com/latest_transactions") - : () => - openInNewTab( - "https://docs.sanchogov.tools/faqs/ways-to-use-your-voting-power", - ) - } - secondButtonLabel={ - pendingTransaction.delegate - ? t("seeTransaction") - : currentDelegation - ? "" - : t("learnMore") - } - title={ - pendingTransaction.delegate ? ( - t("dashboard.delegation.votingPowerDelegation") - ) : currentDelegation ? ( - - ) : ( - t("dashboard.delegation.useYourVotingPower") - ) - } + - {/* DELEGATION CARD END */} - {/* REGISTARTION AS DREP CARD */} - - navigateTo( - voter?.isRegisteredAsDRep - ? PATHS.retireAsDrep - : PATHS.registerAsdRep, - ) - } - firstButtonLabel={ - pendingTransaction.registerAsDrep || pendingTransaction.retireAsDrep - ? "" - : t( - `dashboard.registration.${ - voter?.isRegisteredAsDRep ? "retire" : "register" - }`, - ) - } - inProgress={ - !!( - pendingTransaction.registerAsDrep || - pendingTransaction.retireAsDrep || - pendingTransaction.updateMetaData - ) - } - imageURL={IMAGES.govActionRegisterImage} - secondButtonAction={ - pendingTransaction.registerAsDrep || pendingTransaction.retireAsDrep - ? () => openInNewTab("https://adanordic.com/latest_transactions") - : voter?.isRegisteredAsDRep - ? () => { - navigateTo(PATHS.updateMetadata); - } - : () => - openInNewTab( - "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep", - ) - } - secondButtonLabel={ - pendingTransaction.registerAsDrep || pendingTransaction.retireAsDrep - ? t("seeTransaction") - : voter?.isRegisteredAsDRep - ? t("dashboard.registration.changeMetadata") - : t("learnMore") - } - cardId={ - voter?.isRegisteredAsDRep || voter?.wasRegisteredAsDRep - ? dRepIDBech32 - : "" - } - cardTitle={ - voter?.isRegisteredAsDRep || voter?.wasRegisteredAsDRep - ? t("myDRepId") - : "" - } - title={registrationCardTitle} - /> - {/* DREP CARD END */} - {/* SOLE VOTER CARD */} - - } - firstButtonLabel={ - pendingTransaction.registerAsSoleVoter - ? "" - : t( - voter?.isRegisteredAsSoleVoter - ? "dashboard.soleVoter.retire" - : voter?.wasRegisteredAsSoleVoter - ? "dashboard.soleVoter.reRegister" - : "dashboard.soleVoter.register", - ) - } - firstButtonAction={() => - navigateTo( - voter?.isRegisteredAsSoleVoter - ? PATHS.retireAsSoleVoter - : PATHS.registerAsSoleVoter, - ) - } - firstButtonVariant={ - voter?.isRegisteredAsSoleVoter ? "outlined" : "contained" - } - secondButtonLabel={t("learnMore")} - secondButtonAction={() => - openInNewTab( - "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep", - ) - } - secondButtonVariant="outlined" - imageURL={IMAGES.soleVoterImage} - /> - {/* REGISTARTION AS SOLE VOTER CARD END */} - {/* GOV ACTIONS LIST CARD */} - navigate(PATHS.dashboardGovernanceActions)} - firstButtonLabel={t( - `dashboard.govActions.${ - voter?.isRegisteredAsDRep ? "reviewAndVote" : "view" - }`, - )} - imageURL={IMAGES.govActionListImage} - title={t("dashboard.govActions.title")} + + - {/* GOV ACTIONS LIST CARD END */} - {/* GOV ACTIONS LIST CARD */} - - openInNewTab( - "https://docs.sanchogov.tools/faqs/what-is-a-governance-action", - ) - } - secondButtonVariant="outlined" - imageURL={IMAGES.proposeGovActionImage} - title={t("dashboard.proposeGovernanceAction.title")} + + - {/* GOV ACTIONS LIST CARD END */} + + + + ); }; diff --git a/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx new file mode 100644 index 000000000..9f3bd4301 --- /dev/null +++ b/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx @@ -0,0 +1,144 @@ +import { useCallback, useMemo } from "react"; +import { useNavigate } from "react-router-dom"; + +import { IMAGES, PATHS } from "@consts"; +import { useTranslation } from "@hooks"; +import { DashboardActionCard } from "@molecules"; +import { openInNewTab } from "@utils"; +import { PendingTransaction } from "@/context/pendingTransaction"; +import { VoterInfo } from "@/models"; + +type DRepDashboardCardProps = { + dRepIDBech32: string; + isPendingTransaction: () => boolean; + pendingTransaction: PendingTransaction; + voter: VoterInfo; +}; + +export const DRepDashboardCard = ({ + dRepIDBech32, + isPendingTransaction, + pendingTransaction, + voter, +}: DRepDashboardCardProps) => { + const navigate = useNavigate(); + const { t } = useTranslation(); + + const navigateTo = useCallback( + (path: string) => { + const isPendingTx = isPendingTransaction(); + if (isPendingTx) return; + navigate(path); + }, + [isPendingTransaction, navigate] + ); + + const registrationCardDescription = useMemo(() => { + if (pendingTransaction.registerAsDrep) return t("dashboard.registration.registrationInProgress"); + + if (pendingTransaction.retireAsDrep) return t("dashboard.registration.retirementInProgress"); + + if (pendingTransaction.updateMetaData) return t("dashboard.registration.metadataUpdateInProgress"); + + if (voter?.isRegisteredAsDRep || voter?.wasRegisteredAsDRep) return t("dashboard.registration.holdersCanDelegate"); + + return t("dashboard.registration.ifYouWant"); + }, [ + pendingTransaction, + voter?.isRegisteredAsDRep, + voter?.wasRegisteredAsDRep, + ]); + + const registrationCardTitle = useMemo(() => { + if (pendingTransaction.retireAsDrep) return t("dashboard.registration.dRepRetirement"); + + if (pendingTransaction.registerAsDrep) return t("dashboard.registration.dRepRegistration"); + + if (pendingTransaction.updateMetaData) return t("dashboard.registration.dRepUpdate"); + + if (voter?.isRegisteredAsDRep) return t("dashboard.registration.youAreRegistered"); + + if (voter?.wasRegisteredAsDRep) return t("dashboard.registration.registerAgain"); + + return t("dashboard.registration.registerAsDRep"); + }, [ + pendingTransaction, + voter?.isRegisteredAsDRep, + voter?.wasRegisteredAsDRep, + ]); + + return ( + navigateTo(PATHS.retireAsDrep) + : () => navigateTo(PATHS.registerAsdRep) + } + firstButtonLabel={ + pendingTransaction.registerAsDrep || pendingTransaction.retireAsDrep + ? "" + : t( + `dashboard.registration.${ + voter?.isRegisteredAsDRep ? "retire" : "register" + }` + ) + } + inProgress={ + !!( + pendingTransaction.registerAsDrep || + pendingTransaction.retireAsDrep || + pendingTransaction.updateMetaData + ) + } + imageURL={IMAGES.govActionRegisterImage} + secondButtonAction={ + pendingTransaction.registerAsDrep || pendingTransaction.retireAsDrep + ? () => openInNewTab("https://adanordic.com/latest_transactions") + : voter?.isRegisteredAsDRep + ? () => { + navigateTo(PATHS.updateMetadata); + } + : () => + openInNewTab( + "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep" + ) + } + secondButtonLabel={ + pendingTransaction.registerAsDrep || pendingTransaction.retireAsDrep + ? t("seeTransaction") + : voter?.isRegisteredAsDRep + ? t("dashboard.registration.changeMetadata") + : t("learnMore") + } + cardId={ + voter?.isRegisteredAsDRep || voter?.wasRegisteredAsDRep + ? dRepIDBech32 + : "" + } + cardTitle={ + voter?.isRegisteredAsDRep || voter?.wasRegisteredAsDRep + ? t("myDRepId") + : "" + } + title={registrationCardTitle} + /> + ); +}; diff --git a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx new file mode 100644 index 000000000..81ad86d6b --- /dev/null +++ b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx @@ -0,0 +1,207 @@ +import { useCallback, useMemo } from "react"; +import { useNavigate } from "react-router-dom"; +import { Trans } from "react-i18next"; + +import { IMAGES, PATHS } from "@consts"; +import { useTranslation } from "@hooks"; +import { DashboardActionCard } from "@molecules"; +import { correctAdaFormat, formHexToBech32, openInNewTab } from "@utils"; +import { PendingTransaction } from "@/context/pendingTransaction"; + +type DelegateDashboardCardProps = { + currentDelegation: string; + dRepID: string; + isPendingTransaction: () => boolean; + pendingTransaction: PendingTransaction; + votingPower: number; +}; + +export const DelegateDashboardCard = ({ + currentDelegation, + dRepID, + isPendingTransaction, + pendingTransaction, + votingPower, +}: DelegateDashboardCardProps) => { + const navigate = useNavigate(); + const { t } = useTranslation(); + + const delegationDescription = useMemo(() => { + const correctAdaRepresentation = correctAdaFormat(votingPower); + if (currentDelegation === dRepID) { + return ( + + ); + } if (currentDelegation === "drep_always_no_confidence") { + return ( + + ); + } if (currentDelegation === "drep_always_abstain") { + return ( + + ); + } if (currentDelegation) { + return ( + + ); + } + return ( + + ); + }, [currentDelegation, dRepID, votingPower]); + + const delegationStatusTestForId = useMemo(() => { + if (currentDelegation === dRepID) { + return "myself"; + } if (currentDelegation === "drep_always_no_confidence") { + return "no-confidence"; + } if (currentDelegation === "drep_always_abstain") { + return "abstain"; + } if (currentDelegation) { + return "dRep"; + } + return "not_delegated"; + }, [currentDelegation, dRepID, votingPower]); + + const progressDescription = useMemo(() => { + const correctAdaRepresentation = correctAdaFormat(votingPower); + if (!pendingTransaction.delegate) return; + const { resourceId } = pendingTransaction.delegate; + if (resourceId === dRepID) { + return ( + + ); + } + if (resourceId === "no confidence") { + return ( + + ); + } + if (resourceId === "abstain") { + return ( + + ); + } + if (resourceId) { + return ( + + ); + } + }, [pendingTransaction, dRepID, votingPower]); + + const navigateTo = useCallback( + (path: string) => { + const isPendingTx = isPendingTransaction(); + if (isPendingTx) return; + navigate(path); + }, + [isPendingTransaction, navigate] + ); + + const displayedDelegationId = useMemo(() => { + const restrictedNames = [ + dRepID, + "drep_always_abstain", + "drep_always_no_confidence", + "abstain", + "no confidence", + ]; + if (pendingTransaction.delegate) { + const delegateTo = pendingTransaction.delegate.resourceId; + if (!restrictedNames.includes(delegateTo)) { + return delegateTo.includes("drep") + ? delegateTo + : formHexToBech32(delegateTo); + } + return undefined; + } + if (!restrictedNames.includes(currentDelegation)) { + return formHexToBech32(currentDelegation); + } + return undefined; + }, [currentDelegation, dRepID, pendingTransaction, formHexToBech32]); + + return ( + navigateTo(PATHS.delegateTodRep)} + firstButtonLabel={ + pendingTransaction.delegate + ? "" + : currentDelegation + ? t("dashboard.delegation.changeDelegation") + : t("delegate") + } + firstButtonVariant={currentDelegation ? "outlined" : "contained"} + imageURL={IMAGES.govActionDelegateImage} + cardId={displayedDelegationId} + inProgress={!!pendingTransaction.delegate} + cardTitle={t("dashboard.delegation.dRepDelegatedTo")} + secondButtonAction={ + pendingTransaction.delegate + ? () => openInNewTab("https://adanordic.com/latest_transactions") + : () => + openInNewTab( + "https://docs.sanchogov.tools/faqs/ways-to-use-your-voting-power" + ) + } + secondButtonLabel={ + pendingTransaction.delegate + ? t("seeTransaction") + : currentDelegation + ? "" + : t("learnMore") + } + title={ + pendingTransaction.delegate ? ( + t("dashboard.delegation.votingPowerDelegation") + ) : currentDelegation ? ( + + ) : ( + t("dashboard.delegation.useYourVotingPower") + ) + } + /> + ); +}; diff --git a/govtool/frontend/src/components/organisms/DashboardCards/ListGovActionsDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/ListGovActionsDashboardCard.tsx new file mode 100644 index 000000000..2d384468d --- /dev/null +++ b/govtool/frontend/src/components/organisms/DashboardCards/ListGovActionsDashboardCard.tsx @@ -0,0 +1,30 @@ +import { useNavigate } from "react-router-dom"; + +import { IMAGES, PATHS } from "@consts"; +import { useTranslation } from "@hooks"; +import { DashboardActionCard } from "@molecules"; +import { VoterInfo } from "@/models"; + +type ListGovActionsDashboardCardsProps = { + voter: VoterInfo; +}; + +export const ListGovActionsDashboardCards = ({ voter }: ListGovActionsDashboardCardsProps) => { + const navigate = useNavigate(); + const { t } = useTranslation(); + + return ( + navigate(PATHS.dashboardGovernanceActions)} + firstButtonLabel={t( + `dashboard.govActions.${ + voter?.isRegisteredAsDRep ? "reviewAndVote" : "view" + }` + )} + imageURL={IMAGES.govActionListImage} + title={t("dashboard.govActions.title")} + /> + ); +}; diff --git a/govtool/frontend/src/components/organisms/DashboardCards/ProposeGovActionDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/ProposeGovActionDashboardCard.tsx new file mode 100644 index 000000000..b61f8869c --- /dev/null +++ b/govtool/frontend/src/components/organisms/DashboardCards/ProposeGovActionDashboardCard.tsx @@ -0,0 +1,49 @@ +import { useCallback } from "react"; +import { useNavigate } from "react-router-dom"; + +import { IMAGES, PATHS } from "@consts"; +import { useTranslation } from "@hooks"; +import { DashboardActionCard } from "@molecules"; +import { openInNewTab } from "@utils"; +import { PendingTransaction } from "@/context/pendingTransaction"; + +type ProposeGovActionDashboardCardProps = { + pendingTransaction: PendingTransaction; +}; + +export const ProposeGovActionDashboardCard = ({ + pendingTransaction, +}: ProposeGovActionDashboardCardProps) => { + const navigate = useNavigate(); + const { t } = useTranslation(); + + const onClickGovernanceActionCardActionButton = useCallback(() => { + if (!pendingTransaction.createGovAction) { + navigate(PATHS.dashboardGovernanceActions); + return; + } + navigate(PATHS.createGovernanceAction); + }, [pendingTransaction, navigate]); + + return ( + + openInNewTab( + "https://docs.sanchogov.tools/faqs/what-is-a-governance-action" + )} + secondButtonVariant="outlined" + imageURL={IMAGES.proposeGovActionImage} + title={t("dashboard.proposeGovernanceAction.title")} + /> + ); +}; diff --git a/govtool/frontend/src/components/organisms/DashboardCards/SoleVoterDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/SoleVoterDashboardCard.tsx new file mode 100644 index 000000000..ace447c0c --- /dev/null +++ b/govtool/frontend/src/components/organisms/DashboardCards/SoleVoterDashboardCard.tsx @@ -0,0 +1,117 @@ +import { useCallback, useMemo } from "react"; +import { useNavigate } from "react-router-dom"; +import { Trans } from "react-i18next"; + +import { IMAGES, PATHS } from "@consts"; +import { useTranslation } from "@hooks"; +import { DashboardActionCard } from "@molecules"; +import { correctAdaFormat, openInNewTab } from "@utils"; +import { PendingTransaction } from "@/context/pendingTransaction"; +import { VoterInfo } from "@/models"; + +type SoleVoterDashboardCardProps = { + isPendingTransaction: () => boolean; + pendingTransaction: PendingTransaction; + voter: VoterInfo; + votingPower: number; +}; + +export const SoleVoterDashboardCard = ({ + isPendingTransaction, + pendingTransaction, + voter, + votingPower, +}: SoleVoterDashboardCardProps) => { + const navigate = useNavigate(); + const { t } = useTranslation(); + + const navigateTo = useCallback( + (path: string) => { + const isPendingTx = isPendingTransaction(); + if (isPendingTx) return; + navigate(path); + }, + [isPendingTransaction, navigate] + ); + + const soleVoterCardDescription = useMemo(() => { + if (pendingTransaction.registerAsSoleVoter) return "dashboard.soleVoter.registrationInProgress"; + + if (pendingTransaction.retireAsSoleVoter) return "dashboard.soleVoter.retirementInProgress"; + + if (voter?.isRegisteredAsSoleVoter) return "dashboard.soleVoter.isRegisteredDescription"; + + if (voter?.wasRegisteredAsSoleVoter) return "dashboard.soleVoter.wasRegisteredDescription"; + + return "dashboard.soleVoter.registerDescription"; + }, [ + pendingTransaction, + voter?.isRegisteredAsSoleVoter, + voter?.wasRegisteredAsSoleVoter, + ]); + + const soleVoterCardTitle = useMemo(() => { + if (pendingTransaction.retireAsSoleVoter) return t("dashboard.soleVoter.retirement"); + + if (pendingTransaction.registerAsSoleVoter) return t("dashboard.soleVoter.registration"); + + if (voter?.isRegisteredAsSoleVoter) return t("dashboard.soleVoter.youAreSoleVoterTitle"); + + if (voter?.wasRegisteredAsSoleVoter) return t("dashboard.soleVoter.wasSoleVoterTitle"); + + return t("dashboard.soleVoter.registerTitle"); + }, [ + pendingTransaction, + voter?.isRegisteredAsSoleVoter, + voter?.isRegisteredAsSoleVoter, + ]); + + return ( + + )} + firstButtonLabel={ + pendingTransaction.registerAsSoleVoter + ? "" + : t( + voter?.isRegisteredAsSoleVoter + ? "dashboard.soleVoter.retire" + : voter?.wasRegisteredAsSoleVoter + ? "dashboard.soleVoter.reRegister" + : "dashboard.soleVoter.register" + ) + } + firstButtonAction={() => + navigateTo( + voter?.isRegisteredAsSoleVoter + ? PATHS.retireAsSoleVoter + : PATHS.registerAsSoleVoter + )} + firstButtonVariant={ + voter?.isRegisteredAsSoleVoter ? "outlined" : "contained" + } + secondButtonLabel={t("learnMore")} + secondButtonAction={() => + openInNewTab( + "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep" + )} + secondButtonVariant="outlined" + imageURL={IMAGES.soleVoterImage} + /> + ); +}; From 3ba91d2be0c6426d32c30799012180e99a8db0ad Mon Sep 17 00:00:00 2001 From: Joanna Dyczka Date: Wed, 20 Mar 2024 13:25:04 +0100 Subject: [PATCH 2/2] [#541] refactor dashboard cards --- .../frontend/src/components/atoms/types.ts | 1 + .../src/components/molecules/Card.tsx | 2 +- .../src/components/molecules/CopyableInfo.tsx | 47 +++ .../src/components/molecules/DRepInfoCard.tsx | 8 +- .../molecules/DashboardActionCard.tsx | 222 ++++-------- .../components/molecules/WalletInfoCard.tsx | 18 +- .../src/components/molecules/index.ts | 1 + .../components/organisms/DashboardCards.tsx | 11 +- .../DashboardCards/DRepDashboardCard.tsx | 217 ++++++------ .../DashboardCards/DelegateDashboardCard.tsx | 320 ++++++++---------- .../ListGovActionsDashboardCard.tsx | 18 +- .../ProposeGovActionDashboardCard.tsx | 58 ++-- .../DashboardCards/SoleVoterDashboardCard.tsx | 170 +++++----- .../src/stories/DashboardCard.stories.ts | 27 +- 14 files changed, 525 insertions(+), 595 deletions(-) create mode 100644 govtool/frontend/src/components/molecules/CopyableInfo.tsx diff --git a/govtool/frontend/src/components/atoms/types.ts b/govtool/frontend/src/components/atoms/types.ts index ff2e603b8..9d9f959a0 100644 --- a/govtool/frontend/src/components/atoms/types.ts +++ b/govtool/frontend/src/components/atoms/types.ts @@ -11,6 +11,7 @@ import * as TooltipMUI from "@mui/material/Tooltip"; export type ButtonProps = Omit & { size?: "small" | "medium" | "large" | "extraLarge"; + dataTestId?: string; }; export type LoadingButtonProps = ButtonProps & { diff --git a/govtool/frontend/src/components/molecules/Card.tsx b/govtool/frontend/src/components/molecules/Card.tsx index c1c5dceff..a6ef31177 100644 --- a/govtool/frontend/src/components/molecules/Card.tsx +++ b/govtool/frontend/src/components/molecules/Card.tsx @@ -39,7 +39,7 @@ export const Card = ({ variant = "default", border = variant !== "default", children, - elevation = 4, + elevation = 3, label, sx, }: CardProps) => { diff --git a/govtool/frontend/src/components/molecules/CopyableInfo.tsx b/govtool/frontend/src/components/molecules/CopyableInfo.tsx new file mode 100644 index 000000000..60597f572 --- /dev/null +++ b/govtool/frontend/src/components/molecules/CopyableInfo.tsx @@ -0,0 +1,47 @@ +import { Box, Typography } from "@mui/material"; + +import { CopyButton } from "@atoms"; +import { Card } from "./Card"; +import { gray } from "@/consts"; + +type CopyableInfoProps = { + dataTestId?: string; + label: string; + value: string; +}; + +export const CopyableInfo = ({ + dataTestId, + label, + value, +}: CopyableInfoProps) => ( + theme.palette.neutralWhite, + }} + > + + + {label} + + + + + + {value} + + + +); diff --git a/govtool/frontend/src/components/molecules/DRepInfoCard.tsx b/govtool/frontend/src/components/molecules/DRepInfoCard.tsx index f01d31897..00663ea63 100644 --- a/govtool/frontend/src/components/molecules/DRepInfoCard.tsx +++ b/govtool/frontend/src/components/molecules/DRepInfoCard.tsx @@ -3,15 +3,17 @@ import { Box, Typography } from "@mui/material"; import { useCardano } from "@context"; import { CopyButton } from "@atoms"; import { useTranslation } from "@hooks"; +import { Card } from "./Card"; +import { gray } from "@/consts"; export const DRepInfoCard = () => { const { dRepIDBech32 } = useCardano(); const { t } = useTranslation(); return ( - + - + {t("myDRepId")} @@ -28,6 +30,6 @@ export const DRepInfoCard = () => { {dRepIDBech32} - + ); }; diff --git a/govtool/frontend/src/components/molecules/DashboardActionCard.tsx b/govtool/frontend/src/components/molecules/DashboardActionCard.tsx index 29d9cd940..55dde49ad 100644 --- a/govtool/frontend/src/components/molecules/DashboardActionCard.tsx +++ b/govtool/frontend/src/components/molecules/DashboardActionCard.tsx @@ -1,30 +1,18 @@ -import { Box, ButtonProps, Skeleton } from "@mui/material"; +import { Box, Skeleton } from "@mui/material"; import { FC, ReactNode } from "react"; -import { CopyButton, LoadingButton, Typography } from "@atoms"; +import { LoadingButton, LoadingButtonProps, Typography } from "@atoms"; import { useScreenDimension, useTranslation } from "@hooks"; -import { theme } from "@/theme"; +import { Card } from "./Card"; -type DashboardActionCardProps = { - cardId?: string; - cardTitle?: string; +export type DashboardActionCardProps = { + buttons?: LoadingButtonProps[]; + children?: ReactNode; dataTestidDelegationStatus?: string; - dataTestidDrepIdBox?: string; - dataTestidFirstButton?: string; - dataTestidSecondButton?: string; description?: ReactNode; - firstButtonAction?: () => void; - firstButtonDisabled?: boolean; - firstButtonIsLoading?: boolean; - firstButtonLabel?: string; - firstButtonVariant?: ButtonProps["variant"]; imageURL?: string; - inProgress?: boolean; isLoading?: boolean; - secondButtonAction?: () => void; - secondButtonIsLoading?: boolean; - secondButtonLabel?: string; - secondButtonVariant?: ButtonProps["variant"]; + state?: "active" | "inProgress" | "default"; title?: ReactNode; }; @@ -33,62 +21,32 @@ export const DashboardActionCard: FC = ({ }) => { const { t } = useTranslation(); const { - cardId, - cardTitle, - dataTestidDrepIdBox, - dataTestidFirstButton, - dataTestidSecondButton, + buttons, + children, description, - firstButtonAction, - firstButtonDisabled = false, - firstButtonIsLoading = false, - firstButtonLabel, - firstButtonVariant = "contained", imageURL, - inProgress, isLoading = false, - secondButtonAction, - secondButtonIsLoading = false, - secondButtonLabel, - secondButtonVariant = "outlined", + state = "default", title, } = props; - const { - palette: { boxShadow2 }, - } = theme; - const { isMobile, screenWidth } = useScreenDimension(); + const { screenWidth } = useScreenDimension(); return ( - - {inProgress && !isLoading && ( - - - {t("inProgress")} - - - )} {imageURL ? ( isLoading ? ( @@ -113,7 +71,7 @@ export const DashboardActionCard: FC = ({ {isLoading ? : title} ) : null} - {inProgress && !isLoading ? ( + {state === "inProgress" && !isLoading ? ( {t("inProgress")} @@ -122,7 +80,7 @@ export const DashboardActionCard: FC = ({ @@ -133,102 +91,46 @@ export const DashboardActionCard: FC = ({ )} ) : null} - {cardId && ( - - - - {cardTitle} - - - {cardId} - - - - - )} - {isLoading ? ( - - - - - ) : ( - - {firstButtonLabel ? ( - - {firstButtonLabel} - - ) : null} - {secondButtonLabel ? ( + {children} + + {isLoading ? ( + <> + + + + ) : ( + buttons?.map(({ dataTestId, ...buttonProps }) => ( - {secondButtonLabel} - - ) : null} - - )} - + {...buttonProps} + /> + )) + )} + + ); }; diff --git a/govtool/frontend/src/components/molecules/WalletInfoCard.tsx b/govtool/frontend/src/components/molecules/WalletInfoCard.tsx index d45dd3e31..b9d3a482c 100644 --- a/govtool/frontend/src/components/molecules/WalletInfoCard.tsx +++ b/govtool/frontend/src/components/molecules/WalletInfoCard.tsx @@ -1,9 +1,10 @@ import { useNavigate } from "react-router-dom"; import { Box, Button, Typography } from "@mui/material"; -import { PATHS } from "@consts"; +import { PATHS, gray } from "@consts"; import { useCardano } from "@context"; import { useTranslation } from "@hooks"; +import { Card } from "./Card"; export const WalletInfoCard = () => { const { address, disconnectWallet } = useCardano(); @@ -18,17 +19,8 @@ export const WalletInfoCard = () => { return ( address && ( - - + + {t("wallet.connectedWallet")} @@ -52,7 +44,7 @@ export const WalletInfoCard = () => { {t("wallet.disconnect")} - + ) ); }; diff --git a/govtool/frontend/src/components/molecules/index.ts b/govtool/frontend/src/components/molecules/index.ts index 78d4f0563..49002a007 100644 --- a/govtool/frontend/src/components/molecules/index.ts +++ b/govtool/frontend/src/components/molecules/index.ts @@ -3,6 +3,7 @@ export * from "./Breadcrumbs"; export * from "./Card"; export * from "./CenteredBoxBottomButtons"; export * from "./CenteredBoxPageWrapper"; +export * from "./CopyableInfo"; export * from "./DashboardActionCard"; export * from "./DataActionsBar"; export * from "./DataMissingInfoBox"; diff --git a/govtool/frontend/src/components/organisms/DashboardCards.tsx b/govtool/frontend/src/components/organisms/DashboardCards.tsx index 051c70b91..ec7747cf3 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards.tsx @@ -1,4 +1,5 @@ import { Box, CircularProgress } from "@mui/material"; + import { useCardano } from "@context"; import { useGetAdaHolderVotingPowerQuery, @@ -16,7 +17,6 @@ export const DashboardCards = () => { const { dRepID, dRepIDBech32, - isPendingTransaction, pendingTransaction, stakeKey, } = useCardano(); @@ -61,21 +61,18 @@ export const DashboardCards = () => { > { - + ); }; diff --git a/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx index 9f3bd4301..4c9298d3e 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx @@ -1,144 +1,133 @@ -import { useCallback, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { IMAGES, PATHS } from "@consts"; import { useTranslation } from "@hooks"; -import { DashboardActionCard } from "@molecules"; +import { + CopyableInfo, + DashboardActionCard, + DashboardActionCardProps, +} from "@molecules"; import { openInNewTab } from "@utils"; import { PendingTransaction } from "@/context/pendingTransaction"; import { VoterInfo } from "@/models"; type DRepDashboardCardProps = { dRepIDBech32: string; - isPendingTransaction: () => boolean; pendingTransaction: PendingTransaction; voter: VoterInfo; }; export const DRepDashboardCard = ({ dRepIDBech32, - isPendingTransaction, pendingTransaction, voter, }: DRepDashboardCardProps) => { const navigate = useNavigate(); const { t } = useTranslation(); - const navigateTo = useCallback( - (path: string) => { - const isPendingTx = isPendingTransaction(); - if (isPendingTx) return; - navigate(path); - }, - [isPendingTransaction, navigate] + const inProgress = !!( + pendingTransaction.registerAsDrep || + pendingTransaction.retireAsDrep || + pendingTransaction.updateMetaData ); - const registrationCardDescription = useMemo(() => { - if (pendingTransaction.registerAsDrep) return t("dashboard.registration.registrationInProgress"); - - if (pendingTransaction.retireAsDrep) return t("dashboard.registration.retirementInProgress"); - - if (pendingTransaction.updateMetaData) return t("dashboard.registration.metadataUpdateInProgress"); - - if (voter?.isRegisteredAsDRep || voter?.wasRegisteredAsDRep) return t("dashboard.registration.holdersCanDelegate"); - - return t("dashboard.registration.ifYouWant"); - }, [ - pendingTransaction, - voter?.isRegisteredAsDRep, - voter?.wasRegisteredAsDRep, - ]); - - const registrationCardTitle = useMemo(() => { - if (pendingTransaction.retireAsDrep) return t("dashboard.registration.dRepRetirement"); - - if (pendingTransaction.registerAsDrep) return t("dashboard.registration.dRepRegistration"); - - if (pendingTransaction.updateMetaData) return t("dashboard.registration.dRepUpdate"); - - if (voter?.isRegisteredAsDRep) return t("dashboard.registration.youAreRegistered"); - - if (voter?.wasRegisteredAsDRep) return t("dashboard.registration.registerAgain"); - - return t("dashboard.registration.registerAsDRep"); - }, [ - pendingTransaction, - voter?.isRegisteredAsDRep, - voter?.wasRegisteredAsDRep, - ]); + const cardProps: Partial = (() => { + // transaction in progress + if (inProgress) { + return { + buttons: [ + { + children: t("seeTransaction"), + onClick: () => + openInNewTab("https://adanordic.com/latest_transactions"), + }, + ], + state: "inProgress", + ...(pendingTransaction.registerAsDrep && { + description: t("dashboard.registration.registrationInProgress"), + title: t("dashboard.registration.dRepRegistration"), + }), + ...(pendingTransaction.retireAsDrep && { + description: t("dashboard.registration.retirementInProgress"), + title: t("dashboard.registration.dRepRetirement"), + }), + ...(pendingTransaction.updateMetaData && { + description: t("dashboard.registration.metadataUpdateInProgress"), + title: t("dashboard.registration.dRepUpdate"), + }), + }; + } + + // currently registered + if (voter?.isRegisteredAsDRep) { + return { + buttons: [ + { + children: t("dashboard.registration.retire"), + dataTestId: "retire-button", + onClick: () => navigate(PATHS.retireAsDrep), + }, + { + children: t("dashboard.registration.changeMetadata"), + dataTestId: "change-metadata-button", + onClick: () => navigate(PATHS.updateMetadata), + variant: "text", + }, + ], + description: t("dashboard.registration.holdersCanDelegate"), + state: "active", + title: t("dashboard.registration.youAreRegistered"), + }; + } + + // common buttons for was registered or not registered + const wasRegisteredOrNotRegisteredButtons: DashboardActionCardProps["buttons"] = + [ + { + children: t("dashboard.registration.register"), + dataTestId: "register-button", + onClick: () => navigate(PATHS.registerAsdRep), + variant: "contained", + }, + { + children: t("learnMore"), + dataTestId: "register-learn-more-button", + onClick: () => + openInNewTab( + "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep" + ), + }, + ]; + + // was registered + if (voter?.wasRegisteredAsDRep) { + return { + buttons: wasRegisteredOrNotRegisteredButtons, + description: t("dashboard.registration.holdersCanDelegate"), + title: t("dashboard.registration.registerAgain"), + }; + } + + // not registered + return { + buttons: wasRegisteredOrNotRegisteredButtons, + description: t("dashboard.registration.ifYouWant"), + title: t("dashboard.registration.registerAsDRep"), + }; + })(); return ( navigateTo(PATHS.retireAsDrep) - : () => navigateTo(PATHS.registerAsdRep) - } - firstButtonLabel={ - pendingTransaction.registerAsDrep || pendingTransaction.retireAsDrep - ? "" - : t( - `dashboard.registration.${ - voter?.isRegisteredAsDRep ? "retire" : "register" - }` - ) - } - inProgress={ - !!( - pendingTransaction.registerAsDrep || - pendingTransaction.retireAsDrep || - pendingTransaction.updateMetaData - ) - } imageURL={IMAGES.govActionRegisterImage} - secondButtonAction={ - pendingTransaction.registerAsDrep || pendingTransaction.retireAsDrep - ? () => openInNewTab("https://adanordic.com/latest_transactions") - : voter?.isRegisteredAsDRep - ? () => { - navigateTo(PATHS.updateMetadata); - } - : () => - openInNewTab( - "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep" - ) - } - secondButtonLabel={ - pendingTransaction.registerAsDrep || pendingTransaction.retireAsDrep - ? t("seeTransaction") - : voter?.isRegisteredAsDRep - ? t("dashboard.registration.changeMetadata") - : t("learnMore") - } - cardId={ - voter?.isRegisteredAsDRep || voter?.wasRegisteredAsDRep - ? dRepIDBech32 - : "" - } - cardTitle={ - voter?.isRegisteredAsDRep || voter?.wasRegisteredAsDRep - ? t("myDRepId") - : "" - } - title={registrationCardTitle} - /> + {...cardProps} + > + {(voter?.isRegisteredAsDRep || voter?.wasRegisteredAsDRep) && ( + + )} + ); }; diff --git a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx index 81ad86d6b..6f68f06a9 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx @@ -1,207 +1,185 @@ -import { useCallback, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { Trans } from "react-i18next"; import { IMAGES, PATHS } from "@consts"; import { useTranslation } from "@hooks"; -import { DashboardActionCard } from "@molecules"; +import { + CopyableInfo, + DashboardActionCard, + DashboardActionCardProps, +} from "@molecules"; import { correctAdaFormat, formHexToBech32, openInNewTab } from "@utils"; import { PendingTransaction } from "@/context/pendingTransaction"; type DelegateDashboardCardProps = { currentDelegation: string; + delegateTx: PendingTransaction["delegate"]; dRepID: string; - isPendingTransaction: () => boolean; - pendingTransaction: PendingTransaction; votingPower: number; }; export const DelegateDashboardCard = ({ currentDelegation, + delegateTx, dRepID, - isPendingTransaction, - pendingTransaction, votingPower, }: DelegateDashboardCardProps) => { const navigate = useNavigate(); const { t } = useTranslation(); - const delegationDescription = useMemo(() => { - const correctAdaRepresentation = correctAdaFormat(votingPower); - if (currentDelegation === dRepID) { - return ( - - ); - } if (currentDelegation === "drep_always_no_confidence") { - return ( - - ); - } if (currentDelegation === "drep_always_abstain") { - return ( - - ); - } if (currentDelegation) { - return ( - - ); - } - return ( - - ); - }, [currentDelegation, dRepID, votingPower]); + const ada = correctAdaFormat(votingPower); - const delegationStatusTestForId = useMemo(() => { - if (currentDelegation === dRepID) { - return "myself"; - } if (currentDelegation === "drep_always_no_confidence") { - return "no-confidence"; - } if (currentDelegation === "drep_always_abstain") { - return "abstain"; - } if (currentDelegation) { - return "dRep"; + const cardProps: Partial = (() => { + // transaction in progress + if (delegateTx) { + return { + buttons: [ + { + children: t("seeTransaction"), + dataTestId: "see-transaction-button", + onClick: () => + openInNewTab("https://adanordic.com/latest_transactions"), + }, + ], + description: getProgressDescription( + delegateTx?.resourceId, + dRepID, + ada + ), + state: "inProgress", + title: t("dashboard.delegation.votingPowerDelegation"), + }; } - return "not_delegated"; - }, [currentDelegation, dRepID, votingPower]); - const progressDescription = useMemo(() => { - const correctAdaRepresentation = correctAdaFormat(votingPower); - if (!pendingTransaction.delegate) return; - const { resourceId } = pendingTransaction.delegate; - if (resourceId === dRepID) { - return ( - - ); - } - if (resourceId === "no confidence") { - return ( - - ); - } - if (resourceId === "abstain") { - return ( - - ); + // current delegation + if (currentDelegation) { + return { + buttons: [ + { + children: t("dashboard.delegation.changeDelegation"), + dataTestId: "change-dRep-button", + onClick: () => navigate(PATHS.delegateTodRep), + }, + ], + description: getDelegationDescription(currentDelegation, dRepID, ada), + state: "active", + title: ( + + ), + }; } - if (resourceId) { - return ( + + // no current delegation + return { + buttons: [ + { + children: t("delegate"), + dataTestId: "delegate-button", + onClick: () => navigate(PATHS.delegateTodRep), + variant: "contained", + }, + { + children: t("learnMore"), + dataTestId: "delegate-learn-more-button", + onClick: () => + openInNewTab( + "https://docs.sanchogov.tools/faqs/ways-to-use-your-voting-power" + ), + }, + ], + description: ( - ); - } - }, [pendingTransaction, dRepID, votingPower]); + ), + title: t("dashboard.delegation.useYourVotingPower"), + }; + })(); - const navigateTo = useCallback( - (path: string) => { - const isPendingTx = isPendingTransaction(); - if (isPendingTx) return; - navigate(path); - }, - [isPendingTransaction, navigate] + const displayedDelegationId = getDisplayedDelegationId( + currentDelegation, + delegateTx?.resourceId, + dRepID ); - const displayedDelegationId = useMemo(() => { - const restrictedNames = [ - dRepID, - "drep_always_abstain", - "drep_always_no_confidence", - "abstain", - "no confidence", - ]; - if (pendingTransaction.delegate) { - const delegateTo = pendingTransaction.delegate.resourceId; - if (!restrictedNames.includes(delegateTo)) { - return delegateTo.includes("drep") - ? delegateTo - : formHexToBech32(delegateTo); - } - return undefined; - } - if (!restrictedNames.includes(currentDelegation)) { - return formHexToBech32(currentDelegation); - } - return undefined; - }, [currentDelegation, dRepID, pendingTransaction, formHexToBech32]); - return ( navigateTo(PATHS.delegateTodRep)} - firstButtonLabel={ - pendingTransaction.delegate - ? "" - : currentDelegation - ? t("dashboard.delegation.changeDelegation") - : t("delegate") - } - firstButtonVariant={currentDelegation ? "outlined" : "contained"} imageURL={IMAGES.govActionDelegateImage} - cardId={displayedDelegationId} - inProgress={!!pendingTransaction.delegate} - cardTitle={t("dashboard.delegation.dRepDelegatedTo")} - secondButtonAction={ - pendingTransaction.delegate - ? () => openInNewTab("https://adanordic.com/latest_transactions") - : () => - openInNewTab( - "https://docs.sanchogov.tools/faqs/ways-to-use-your-voting-power" - ) - } - secondButtonLabel={ - pendingTransaction.delegate - ? t("seeTransaction") - : currentDelegation - ? "" - : t("learnMore") - } - title={ - pendingTransaction.delegate ? ( - t("dashboard.delegation.votingPowerDelegation") - ) : currentDelegation ? ( - - ) : ( - t("dashboard.delegation.useYourVotingPower") - ) - } - /> + {...cardProps} + > + {displayedDelegationId && ( + + )} + ); }; + +const getDelegationDescription = ( + currentDelegation: string, + dRepID: string, + ada: number +) => { + const key = + currentDelegation === dRepID + ? "dashboard.delegation.toYourself" + : currentDelegation === "drep_always_no_confidence" + ? "dashboard.delegation.voteNo" + : currentDelegation === "drep_always_abstain" + ? "dashboard.delegation.voteAbstain" + : currentDelegation + ? "dashboard.delegation.toDRep" + : undefined; + return ; +}; + +const getProgressDescription = ( + delegateTo: string, + dRepID: string, + ada: number +) => { + const key = (() => { + if (!delegateTo) return undefined; + switch (delegateTo) { + case dRepID: + return "dashboard.delegation.inProgress.toYourself"; + case "no confidence": + return "dashboard.delegation.inProgress.voteNo"; + case "abstain": + return "dashboard.delegation.inProgress.voteAbstain"; + default: + return "dashboard.delegation.inProgress.toDRep"; + } + })(); + return ; +}; + +const getDisplayedDelegationId = ( + currentDelegation: string, + delegateTo: string | undefined, + dRepID: string +) => { + const restrictedNames = [ + dRepID, + "drep_always_abstain", + "drep_always_no_confidence", + "abstain", + "no confidence", + ]; + if (delegateTo) { + if (!restrictedNames.includes(delegateTo)) { + return delegateTo.includes("drep") + ? delegateTo + : formHexToBech32(delegateTo); + } + return undefined; + } + if (!restrictedNames.includes(currentDelegation)) { + return formHexToBech32(currentDelegation); + } + return undefined; +}; diff --git a/govtool/frontend/src/components/organisms/DashboardCards/ListGovActionsDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/ListGovActionsDashboardCard.tsx index 2d384468d..dfc42cc36 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards/ListGovActionsDashboardCard.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards/ListGovActionsDashboardCard.tsx @@ -15,14 +15,18 @@ export const ListGovActionsDashboardCards = ({ voter }: ListGovActionsDashboardC return ( navigate(PATHS.dashboardGovernanceActions), + }, + ]} description={t("dashboard.govActions.description")} - firstButtonAction={() => navigate(PATHS.dashboardGovernanceActions)} - firstButtonLabel={t( - `dashboard.govActions.${ - voter?.isRegisteredAsDRep ? "reviewAndVote" : "view" - }` - )} imageURL={IMAGES.govActionListImage} title={t("dashboard.govActions.title")} /> diff --git a/govtool/frontend/src/components/organisms/DashboardCards/ProposeGovActionDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/ProposeGovActionDashboardCard.tsx index b61f8869c..6bace3a8d 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards/ProposeGovActionDashboardCard.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards/ProposeGovActionDashboardCard.tsx @@ -1,4 +1,3 @@ -import { useCallback } from "react"; import { useNavigate } from "react-router-dom"; import { IMAGES, PATHS } from "@consts"; @@ -8,41 +7,50 @@ import { openInNewTab } from "@utils"; import { PendingTransaction } from "@/context/pendingTransaction"; type ProposeGovActionDashboardCardProps = { - pendingTransaction: PendingTransaction; + createGovActionTx: PendingTransaction["createGovAction"]; }; export const ProposeGovActionDashboardCard = ({ - pendingTransaction, + createGovActionTx, }: ProposeGovActionDashboardCardProps) => { const navigate = useNavigate(); const { t } = useTranslation(); - const onClickGovernanceActionCardActionButton = useCallback(() => { - if (!pendingTransaction.createGovAction) { - navigate(PATHS.dashboardGovernanceActions); - return; - } - navigate(PATHS.createGovernanceAction); - }, [pendingTransaction, navigate]); - return ( navigate(PATHS.dashboardGovernanceActions), + variant: "contained", + } as const, + ] + // default + : [ + { + children: t("dashboard.proposeGovernanceAction.propose"), + dataTestId: "propose-governance-actions-button", + onClick: () => navigate(PATHS.createGovernanceAction), + variant: "contained", + } as const, + ]), + // common + { + children: t("learnMore"), + dataTestId: "learn-more-button", + onClick: () => + openInNewTab( + "https://docs.sanchogov.tools/faqs/what-is-a-governance-action" + ), + }, + ]} description={t("dashboard.proposeGovernanceAction.description")} - firstButtonAction={onClickGovernanceActionCardActionButton} - firstButtonLabel={t( - `dashboard.proposeGovernanceAction.${ - pendingTransaction.createGovAction ? "view" : "propose" - }` - )} - inProgress={!!pendingTransaction.createGovAction} - secondButtonLabel={t("learnMore")} - secondButtonAction={() => - openInNewTab( - "https://docs.sanchogov.tools/faqs/what-is-a-governance-action" - )} - secondButtonVariant="outlined" imageURL={IMAGES.proposeGovActionImage} + state={createGovActionTx ? "inProgress" : "default"} title={t("dashboard.proposeGovernanceAction.title")} /> ); diff --git a/govtool/frontend/src/components/organisms/DashboardCards/SoleVoterDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/SoleVoterDashboardCard.tsx index ace447c0c..95eb1449b 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards/SoleVoterDashboardCard.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards/SoleVoterDashboardCard.tsx @@ -1,23 +1,21 @@ -import { useCallback, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { Trans } from "react-i18next"; import { IMAGES, PATHS } from "@consts"; import { useTranslation } from "@hooks"; -import { DashboardActionCard } from "@molecules"; +import { DashboardActionCard, DashboardActionCardProps } from "@molecules"; import { correctAdaFormat, openInNewTab } from "@utils"; +import { LoadingButtonProps } from "@atoms"; import { PendingTransaction } from "@/context/pendingTransaction"; import { VoterInfo } from "@/models"; type SoleVoterDashboardCardProps = { - isPendingTransaction: () => boolean; pendingTransaction: PendingTransaction; voter: VoterInfo; votingPower: number; }; export const SoleVoterDashboardCard = ({ - isPendingTransaction, pendingTransaction, voter, votingPower, @@ -25,93 +23,95 @@ export const SoleVoterDashboardCard = ({ const navigate = useNavigate(); const { t } = useTranslation(); - const navigateTo = useCallback( - (path: string) => { - const isPendingTx = isPendingTransaction(); - if (isPendingTx) return; - navigate(path); - }, - [isPendingTransaction, navigate] - ); - - const soleVoterCardDescription = useMemo(() => { - if (pendingTransaction.registerAsSoleVoter) return "dashboard.soleVoter.registrationInProgress"; - - if (pendingTransaction.retireAsSoleVoter) return "dashboard.soleVoter.retirementInProgress"; - - if (voter?.isRegisteredAsSoleVoter) return "dashboard.soleVoter.isRegisteredDescription"; - - if (voter?.wasRegisteredAsSoleVoter) return "dashboard.soleVoter.wasRegisteredDescription"; + const ada = correctAdaFormat(votingPower); - return "dashboard.soleVoter.registerDescription"; - }, [ - pendingTransaction, - voter?.isRegisteredAsSoleVoter, - voter?.wasRegisteredAsSoleVoter, - ]); + const cardProps: Partial = (() => { + // transaction in progress + if ( + !!pendingTransaction.registerAsSoleVoter || + !!pendingTransaction.retireAsSoleVoter + ) { + return { + buttons: [ + { + children: t("seeTransaction"), + dataTestId: "see-transaction-button", + onClick: () => + openInNewTab("https://adanordic.com/latest_transactions"), + }, + ], + state: "inProgress", + ...(pendingTransaction.registerAsSoleVoter && { + description: t("dashboard.soleVoter.registrationInProgress"), + title: t("dashboard.soleVoter.registration"), + }), + ...(pendingTransaction.retireAsSoleVoter && { + description: t("dashboard.soleVoter.retirementInProgress"), + title: t("dashboard.soleVoter.retirement"), + }), + }; + } - const soleVoterCardTitle = useMemo(() => { - if (pendingTransaction.retireAsSoleVoter) return t("dashboard.soleVoter.retirement"); - - if (pendingTransaction.registerAsSoleVoter) return t("dashboard.soleVoter.registration"); + // learn more button + const learnMoreButton: LoadingButtonProps = { + children: t("learnMore"), + dataTestId: "learn-more-button", + onClick: () => + openInNewTab( + "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep" + ), + }; - if (voter?.isRegisteredAsSoleVoter) return t("dashboard.soleVoter.youAreSoleVoterTitle"); + // currently registered + if (voter?.isRegisteredAsSoleVoter) { + return { + buttons: [ + { + children: t("dashboard.soleVoter.retire"), + dataTestId: "retire-as-sole-voter-button", + onClick: () => navigate(PATHS.retireAsSoleVoter), + }, + learnMoreButton, + ], + description: , + state: "active", + title: t("dashboard.soleVoter.youAreSoleVoterTitle"), + }; + } - if (voter?.wasRegisteredAsSoleVoter) return t("dashboard.soleVoter.wasSoleVoterTitle"); + // was registered + if (voter?.wasRegisteredAsSoleVoter) { + return { + buttons: [ + { + children: t("dashboard.soleVoter.reRegister"), + dataTestId: "register-as-sole-voter-button", + onClick: () => navigate(PATHS.registerAsSoleVoter), + }, + learnMoreButton, + ], + description: , + title: t("dashboard.soleVoter.wasSoleVoterTitle"), + }; + } - return t("dashboard.soleVoter.registerTitle"); - }, [ - pendingTransaction, - voter?.isRegisteredAsSoleVoter, - voter?.isRegisteredAsSoleVoter, - ]); + // not registered + return { + buttons: [ + { + children: t("dashboard.soleVoter.register"), + dataTestId: "register-as-sole-voter-button", + onClick: () => navigate(PATHS.registerAsSoleVoter), + variant: "contained", + }, + learnMoreButton, + ], + description: , + title: t("dashboard.soleVoter.registerTitle"), + }; + })(); return ( - - )} - firstButtonLabel={ - pendingTransaction.registerAsSoleVoter - ? "" - : t( - voter?.isRegisteredAsSoleVoter - ? "dashboard.soleVoter.retire" - : voter?.wasRegisteredAsSoleVoter - ? "dashboard.soleVoter.reRegister" - : "dashboard.soleVoter.register" - ) - } - firstButtonAction={() => - navigateTo( - voter?.isRegisteredAsSoleVoter - ? PATHS.retireAsSoleVoter - : PATHS.registerAsSoleVoter - )} - firstButtonVariant={ - voter?.isRegisteredAsSoleVoter ? "outlined" : "contained" - } - secondButtonLabel={t("learnMore")} - secondButtonAction={() => - openInNewTab( - "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep" - )} - secondButtonVariant="outlined" - imageURL={IMAGES.soleVoterImage} - /> + ); }; diff --git a/govtool/frontend/src/stories/DashboardCard.stories.ts b/govtool/frontend/src/stories/DashboardCard.stories.ts index 7574a9f5a..ac4fb83a2 100644 --- a/govtool/frontend/src/stories/DashboardCard.stories.ts +++ b/govtool/frontend/src/stories/DashboardCard.stories.ts @@ -19,10 +19,12 @@ type Story = StoryObj; export const DashboardCardComponent: Story = { args: { + buttons: [ + { children: "first button" }, + { children: "second button" }, + ], description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit.", - firstButtonLabel: "first button", imageURL: IMAGES.govActionDelegateImage, - secondButtonLabel: "second button", title: "Action card", }, play: async ({ canvasElement }) => { @@ -38,21 +40,24 @@ export const DashboardCardComponent: Story = { export const WithDRepIdDashboardCardComponent: Story = { args: { + buttons: [ + { children: "first button" }, + { children: "second button" }, + ], description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit.", - firstButtonLabel: "first button", imageURL: IMAGES.govActionDelegateImage, - secondButtonLabel: "second button", title: "Action card", - cardId: "drep1gwsw9ckkhuwscj9savt5f7u9xsrudw209hne7pggcktzuw5sv32", }, }; export const LoadingDashboardCard: Story = { args: { + buttons: [ + { children: "first button" }, + { children: "second button" }, + ], description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit.", - firstButtonLabel: "first button", imageURL: IMAGES.govActionDelegateImage, - secondButtonLabel: "second button", title: "Action card", isLoading: true, }, @@ -67,12 +72,14 @@ export const LoadingDashboardCard: Story = { export const InProgressDashboardCard: Story = { args: { + buttons: [ + { children: "first button" }, + { children: "second button" }, + ], description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit.", - firstButtonLabel: "first button", imageURL: IMAGES.govActionDelegateImage, - secondButtonLabel: "second button", title: "Action card", - inProgress: true, + state: "inProgress", }, play: async ({ canvasElement }) => { const canvas = within(canvasElement);