diff --git a/CHANGELOG.md b/CHANGELOG.md index 4343c6f17..bad923aad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ changes. - Fix listing voted-on governance actions [Issue 2379](https://github.com/IntersectMBO/govtool/issues/2379) - Fix wronly displayed markdown on slider card [Issue 2263](https://github.com/IntersectMBO/govtool/issues/2316) - fix ada quantities format to avoid thousands when the total is 0 [Issue 2372](https://github.com/IntersectMBO/govtool/issues/2382) +- fix inconsistent display of delegated DRep card during delegation [Issue 2332](https://github.com/IntersectMBO/govtool/issues/2332) ### Changed diff --git a/govtool/frontend/src/hooks/index.ts b/govtool/frontend/src/hooks/index.ts index e2a7c78e7..eba385e57 100644 --- a/govtool/frontend/src/hooks/index.ts +++ b/govtool/frontend/src/hooks/index.ts @@ -4,6 +4,7 @@ export * from "./useDebounce"; export * from "./useDelegateToDrep"; export * from "./useFetchNextPageDetector"; export * from "./useOutsideClick"; +export * from "./usePrevious"; export * from "./useSaveScrollPosition"; export * from "./useScreenDimension"; export * from "./useSlider"; diff --git a/govtool/frontend/src/hooks/usePrevious.test.ts b/govtool/frontend/src/hooks/usePrevious.test.ts new file mode 100644 index 000000000..275bbf1d2 --- /dev/null +++ b/govtool/frontend/src/hooks/usePrevious.test.ts @@ -0,0 +1,47 @@ +import { renderHook } from "@testing-library/react"; +import { describe, it, expect } from "vitest"; +import usePrevious from "./usePrevious"; + +describe("usePrevious hook", () => { + it("should return undefined on the initial render", () => { + const { result } = renderHook(() => usePrevious(0)); + + expect(result.current).toBeUndefined(); + }); + + it("should return the previous value after the state changes", () => { + let value = 0; + + const { result, rerender } = renderHook(() => usePrevious(value)); + + expect(result.current).toBeUndefined(); + + value = 10; + rerender(); + + expect(result.current).toBe(0); + + value = 20; + rerender(); + + expect(result.current).toBe(10); + }); + + it("should handle non-primitive values like objects", () => { + let value = { count: 0 }; + + const { result, rerender } = renderHook(() => usePrevious(value)); + + expect(result.current).toBeUndefined(); + + value = { count: 1 }; + rerender(); + + expect(result.current).toEqual({ count: 0 }); + + value = { count: 2 }; + rerender(); + + expect(result.current).toEqual({ count: 1 }); + }); +}); diff --git a/govtool/frontend/src/hooks/usePrevious.ts b/govtool/frontend/src/hooks/usePrevious.ts new file mode 100644 index 000000000..a144cc552 --- /dev/null +++ b/govtool/frontend/src/hooks/usePrevious.ts @@ -0,0 +1,18 @@ +import { useEffect, useRef } from "react"; + +/** + * Custom React hook to get the previous value of a prop or state. + * @param value The current value to track. + * @returns The previous value of the given input. + */ +function usePrevious(value: T): T | undefined { + const ref = useRef(); + + useEffect(() => { + ref.current = value; // Update the ref value to the current value after render + }, [value]); // Only run if the value changes + + return ref.current; // Return the previous value (ref.current holds the old value) +} + +export default usePrevious; diff --git a/govtool/frontend/src/pages/DRepDirectoryContent.tsx b/govtool/frontend/src/pages/DRepDirectoryContent.tsx index ece2b33e3..bef54617c 100644 --- a/govtool/frontend/src/pages/DRepDirectoryContent.tsx +++ b/govtool/frontend/src/pages/DRepDirectoryContent.tsx @@ -1,4 +1,4 @@ -import { FC, useEffect } from "react"; +import { FC, useEffect, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Box, CircularProgress } from "@mui/material"; @@ -15,11 +15,12 @@ import { import { DataActionsBar, EmptyStateDrepDirectory } from "@molecules"; import { AutomatedVotingOptions, DRepCard } from "@organisms"; import { correctAdaFormat, isSameDRep } from "@utils"; -import { DRepListSort, DRepStatus } from "@models"; +import { DRepData, DRepListSort, DRepStatus } from "@models"; import { AutomatedVotingOptionCurrentDelegation, AutomatedVotingOptionDelegationId, } from "@/types/automatedVotingOptions"; +import usePrevious from "@/hooks/usePrevious"; interface DRepDirectoryContentProps { isConnected?: boolean; @@ -48,6 +49,9 @@ export const DRepDirectoryContent: FC = ({ const { chosenFilters, chosenSorting, setChosenSorting } = dataActionsBarProps; + const [inProgressDelegationDRepData, setInProgressDelegationDRepData] = + useState(undefined); + useEffect(() => { if (!chosenSorting) setChosenSorting(DRepListSort.Random); }, [chosenSorting, setChosenSorting]); @@ -57,6 +61,7 @@ export const DRepDirectoryContent: FC = ({ const { votingPower } = useGetAdaHolderVotingPowerQuery(stakeKey); const { currentDelegation } = useGetAdaHolderCurrentDelegationQuery(stakeKey); const inProgressDelegation = pendingTransaction.delegate?.resourceId; + const prevInProgressDelegation = usePrevious(inProgressDelegation); const { dRep: myDrep } = useGetDRepDetailsQuery(currentDelegation?.dRepView, { enabled: !!inProgressDelegation || !!currentDelegation, @@ -85,6 +90,12 @@ export const DRepDirectoryContent: FC = ({ }, ); + useEffect(() => { + if (!inProgressDelegation && prevInProgressDelegation) { + setInProgressDelegationDRepData(undefined); + } + }, [prevInProgressDelegation, inProgressDelegation]); + if ( (stakeKey && votingPower === undefined) || !dRepList || @@ -103,12 +114,6 @@ export const DRepDirectoryContent: FC = ({ ? [yourselfDRep, ...listedDRepsWithoutYourself] : listedDRepsWithoutYourself; - const inProgressDelegationDRepData = dRepListToDisplay.find( - (dRep) => - dRep.drepId === inProgressDelegation || - dRep.view === inProgressDelegation, - ); - const isAnAutomatedVotingOptionChosen = currentDelegation?.dRepView && (currentDelegation?.dRepView === @@ -216,7 +221,10 @@ export const DRepDirectoryContent: FC = ({ } isMe={isSameDRep(dRep, myDRepId)} isMyDrep={isSameDRep(dRep, currentDelegation?.dRepView)} - onDelegate={() => delegate(dRep.drepId)} + onDelegate={() => { + setInProgressDelegationDRepData(dRep); + delegate(dRep.drepId); + }} /> ))}