From 0a50bb5e33bb8f6ed7457d485a20cc25fc79314d Mon Sep 17 00:00:00 2001 From: Adam Tomaszczyk Date: Tue, 22 Jul 2025 14:58:17 +0200 Subject: [PATCH 01/11] Allow Opening Governance Actions in New Tab from Live Voting Page --- govtool/frontend/src/App.tsx | 52 ++++++++++++------- .../molecules/GovernanceActionCard.tsx | 7 ++- .../organisms/GovernanceActionsToVote.tsx | 28 +--------- .../src/components/organisms/Slider.tsx | 28 ++++------ .../ValidatedGovernanceActionCard.tsx | 3 +- 5 files changed, 52 insertions(+), 66 deletions(-) diff --git a/govtool/frontend/src/App.tsx b/govtool/frontend/src/App.tsx index c4903b4d8..f5f2fd499 100644 --- a/govtool/frontend/src/App.tsx +++ b/govtool/frontend/src/App.tsx @@ -63,28 +63,44 @@ export default () => { }, []); const checkTheWalletIsActive = useCallback(() => { - const hrefCondition = - window.location.pathname === PATHS.home || - window.location.pathname === PATHS.governanceActions || - window.location.pathname === PATHS.governanceActionsAction; + const isWalletAvailable = () => + window.cardano && walletName && Object.keys(window.cardano).includes(walletName); - const walletName = getItemFromLocalStorage(`${WALLET_LS_KEY}_name`); - if (window.cardano) { - const walletExtensions = Object.keys(window.cardano); - if (walletName && walletExtensions.includes(walletName)) { - enable(walletName); - return; + const cleanUpWalletData = () => { + removeItemFromLocalStorage(`${WALLET_LS_KEY}_name`); + removeItemFromLocalStorage(`${WALLET_LS_KEY}_stake_key`); + }; + + const waitForWalletExtension = async () => { + const timeout = 5000; + const interval = 100; + const startTime = Date.now(); + + while (Date.now() - startTime < timeout) { + if (isWalletAvailable()) { + enable(walletName); + return; + } + await new Promise(resolve => setTimeout(resolve, interval)); } - } - if ( - (!window.cardano && walletName) || - (walletName && !Object.keys(window.cardano).includes(walletName)) - ) { - if (!hrefCondition) { + + if (!isOnAllowedPage) { navigate(PATHS.home); } - removeItemFromLocalStorage(`${WALLET_LS_KEY}_name`); - removeItemFromLocalStorage(`${WALLET_LS_KEY}_stake_key`); + cleanUpWalletData(); + }; + + const isOnAllowedPage = [PATHS.home, PATHS.governanceActions, PATHS.governanceActionsAction] + .includes(window.location.pathname); + + const walletName = getItemFromLocalStorage(`${WALLET_LS_KEY}_name`); + + if (!walletName) return; + + if (isWalletAvailable()) { + enable(walletName); + } else { + waitForWalletExtension(); } }, []); diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx index 47c98f6be..263ed05b3 100644 --- a/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx @@ -1,5 +1,6 @@ import { FC } from "react"; import { Box, Skeleton } from "@mui/material"; +import { Link, useLocation } from "react-router-dom"; import { Button } from "@atoms"; import { @@ -39,7 +40,6 @@ export const GovernanceActionCard: FC = ({ inProgress = false, expiryDate, expiryEpochNo, - onClick, createdDate, createdEpochNo, txHash, @@ -58,6 +58,8 @@ export const GovernanceActionCard: FC = ({ bech32Prefix: "gov_action", }); + const location = useLocation(); + return ( = ({ ) : ( diff --git a/govtool/frontend/src/components/organisms/ValidatedGovernanceActionCard.tsx b/govtool/frontend/src/components/organisms/ValidatedGovernanceActionCard.tsx index 4dfe5ae0a..826dfb3d4 100644 --- a/govtool/frontend/src/components/organisms/ValidatedGovernanceActionCard.tsx +++ b/govtool/frontend/src/components/organisms/ValidatedGovernanceActionCard.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { useValidateMutation } from "@/hooks/mutations"; import { MetadataStandard, ProposalData } from "@/models"; -import { GovernanceActionCard } from "../molecules"; +import { GovernanceActionCard } from "@molecules"; type ActionTypeProps = Omit< ProposalData, @@ -14,7 +14,6 @@ type ActionTypeProps = Omit< | "rationale" | "motivation" > & { - onClick?: () => void; inProgress?: boolean; }; export const ValidatedGovernanceActionCard = (props: ActionTypeProps) => { From 7f2432f31f3608e07dc597558e491c1bde33c110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Tue, 22 Jul 2025 22:33:22 +0200 Subject: [PATCH 02/11] fix(#3918): disappearing governance actions for the same tx hash --- CHANGELOG.md | 2 ++ .../organisms/DashboardGovernanceActions.tsx | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25bb40f23..9c630fce7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ changes. ### Fixed +- Fix disappearing proposals in the governance actions list for the same tx hashes [Issue 3918](https://github.com/IntersectMBO/govtool/issues/3918) + ### Changed ### Removed diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx index ccdf0b84c..c129179a9 100644 --- a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx +++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx @@ -88,8 +88,12 @@ export const DashboardGovernanceActions = () => { const prevFilters = usePrevious(queryFilters); const prevSorting = usePrevious(chosenSorting); - const stableFilters = isAdjusting ? prevFilters ?? queryFilters : queryFilters; - const stableSorting = isAdjusting ? prevSorting ?? chosenSorting : chosenSorting; + const stableFilters = isAdjusting + ? prevFilters ?? queryFilters + : queryFilters; + const stableSorting = isAdjusting + ? prevSorting ?? chosenSorting + : chosenSorting; const { proposals, isProposalsLoading } = useGetProposalsQuery({ filters: stableFilters, @@ -109,7 +113,9 @@ export const DashboardGovernanceActions = () => { const filteredActions = proposalCategory.actions.filter((action) => { const hasVote = votes?.some((voteCategory) => voteCategory.actions.some( - (voteAction) => voteAction.proposal.txHash === action.txHash, + (voteAction) => + voteAction.proposal.txHash === action.txHash && + voteAction.proposal.index === action.index, ), ); From 2b7a6c4012c84e30b386111af2fc7a448b208199 Mon Sep 17 00:00:00 2001 From: bosko-m <88723596+bosko-m@users.noreply.github.com> Date: Wed, 23 Jul 2025 10:37:19 +0200 Subject: [PATCH 03/11] Update DashboardGovernanceActions.tsx Signed-off-by: bosko-m <88723596+bosko-m@users.noreply.github.com> --- .../src/components/organisms/DashboardGovernanceActions.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx index c129179a9..d2c28e9ea 100644 --- a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx +++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx @@ -107,6 +107,8 @@ export const DashboardGovernanceActions = () => { debouncedSearchText, ); + if (!votes) return proposals; + // TODO: Black magic - that filtering should be done on the backend const filteredProposals = proposals ?.map((proposalCategory) => { From 84a8fef08ee88af82a25cdee831834796492e756 Mon Sep 17 00:00:00 2001 From: bosko-m <88723596+bosko-m@users.noreply.github.com> Date: Wed, 23 Jul 2025 10:44:30 +0200 Subject: [PATCH 04/11] Update DashboardGovernanceActions.tsx Signed-off-by: bosko-m <88723596+bosko-m@users.noreply.github.com> --- .../src/components/organisms/DashboardGovernanceActions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx index d2c28e9ea..f4d8261cc 100644 --- a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx +++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx @@ -108,7 +108,7 @@ export const DashboardGovernanceActions = () => { ); if (!votes) return proposals; - + // TODO: Black magic - that filtering should be done on the backend const filteredProposals = proposals ?.map((proposalCategory) => { From adc5d071c4427e801861042f7870d73c901ee508 Mon Sep 17 00:00:00 2001 From: bosko-m <88723596+bosko-m@users.noreply.github.com> Date: Wed, 23 Jul 2025 11:20:54 +0200 Subject: [PATCH 05/11] Update DashboardGovernanceActions.tsx Signed-off-by: bosko-m <88723596+bosko-m@users.noreply.github.com> --- .../organisms/DashboardGovernanceActions.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx index f4d8261cc..f86ed5e84 100644 --- a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx +++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx @@ -107,13 +107,14 @@ export const DashboardGovernanceActions = () => { debouncedSearchText, ); + //White Magic :) + const filterOutAlreadyVotedProposals = () => { if (!votes) return proposals; - // TODO: Black magic - that filtering should be done on the backend - const filteredProposals = proposals + return proposals ?.map((proposalCategory) => { const filteredActions = proposalCategory.actions.filter((action) => { - const hasVote = votes?.some((voteCategory) => + const hasVote = votes.some((voteCategory) => voteCategory.actions.some( (voteAction) => voteAction.proposal.txHash === action.txHash && @@ -130,6 +131,9 @@ export const DashboardGovernanceActions = () => { }; }) .filter((category) => category.actions.length > 0); +}; + +const filteredProposals = filterOutAlreadyVotedProposals(); const { state } = useLocation(); const [content, setContent] = useState( From b1049f9f0d7e5d7ed8ade7f1a20430f20ae4b09d Mon Sep 17 00:00:00 2001 From: bosko-m <88723596+bosko-m@users.noreply.github.com> Date: Wed, 23 Jul 2025 11:23:19 +0200 Subject: [PATCH 06/11] Update DashboardGovernanceActions.tsx Signed-off-by: bosko-m <88723596+bosko-m@users.noreply.github.com> --- .../src/components/organisms/DashboardGovernanceActions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx index f86ed5e84..838123327 100644 --- a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx +++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx @@ -107,7 +107,7 @@ export const DashboardGovernanceActions = () => { debouncedSearchText, ); - //White Magic :) + // White Magic :) const filterOutAlreadyVotedProposals = () => { if (!votes) return proposals; From d86def3ddef27c1e6ddba9bd9a90d0a0fcf028a6 Mon Sep 17 00:00:00 2001 From: Adam Tomaszczyk Date: Wed, 23 Jul 2025 12:21:30 +0200 Subject: [PATCH 07/11] Fix Back button on GA category view and tests --- govtool/frontend/src/App.tsx | 5 ++++- .../frontend/src/components/atoms/types.ts | 5 +++++ .../molecules/GovernanceActionCard.tsx | 21 +++++++++++++++++-- .../ValidatedGovernanceActionCard.tsx | 3 ++- .../DashboardGovernanceActionsCategory.tsx | 15 +------------ .../src/pages/GovernanceActionsCategory.tsx | 14 ------------- .../frontend/src/stories/Slider.stories.tsx | 2 +- 7 files changed, 32 insertions(+), 33 deletions(-) diff --git a/govtool/frontend/src/App.tsx b/govtool/frontend/src/App.tsx index f5f2fd499..ce4f54add 100644 --- a/govtool/frontend/src/App.tsx +++ b/govtool/frontend/src/App.tsx @@ -81,7 +81,10 @@ export default () => { enable(walletName); return; } - await new Promise(resolve => setTimeout(resolve, interval)); + // eslint-disable-next-line no-await-in-loop + await new Promise((resolve) => { + setTimeout(resolve, interval); + }); } if (!isOnAllowedPage) { diff --git a/govtool/frontend/src/components/atoms/types.ts b/govtool/frontend/src/components/atoms/types.ts index 52bf82151..3ae4ea5ae 100644 --- a/govtool/frontend/src/components/atoms/types.ts +++ b/govtool/frontend/src/components/atoms/types.ts @@ -1,4 +1,5 @@ import { ChangeEvent } from "react"; +import { LinkProps } from "react-router-dom"; import { ButtonProps as MUIButtonProps, CheckboxProps as MUICheckboxProps, @@ -13,6 +14,10 @@ export type ButtonProps = Omit & { isLoading?: boolean; size?: "small" | "medium" | "large" | "extraLarge"; dataTestId?: string; + to?: LinkProps["to"]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + state?: any; + component?: React.ElementType; }; export type LoadingButtonProps = ButtonProps & { diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx index 263ed05b3..4d091020f 100644 --- a/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx @@ -40,6 +40,7 @@ export const GovernanceActionCard: FC = ({ inProgress = false, expiryDate, expiryEpochNo, + onClick, createdDate, createdEpochNo, txHash, @@ -58,7 +59,8 @@ export const GovernanceActionCard: FC = ({ bech32Prefix: "gov_action", }); - const location = useLocation(); + const pathname = useLocation().pathname.replace(/governance_actions.*/g, "governance_actions"); + const isCategoryView = useLocation().pathname.includes("category"); return ( = ({ ) : (