diff --git a/govtool/frontend/src/App.tsx b/govtool/frontend/src/App.tsx index 77ef3af19..7db190366 100644 --- a/govtool/frontend/src/App.tsx +++ b/govtool/frontend/src/App.tsx @@ -30,14 +30,13 @@ import { removeItemFromLocalStorage, } from "@utils"; import { SetupInterceptors } from "./services"; -import { useGetVoterInfo, useWalletConnectionListener } from "./hooks"; +import { useWalletConnectionListener } from "./hooks"; import { RegisterAsSoleVoter } from "./pages/RegisterAsSoleVoter"; import { CreateGovernanceAction } from "./pages/CreateGovernanceAction"; export default () => { - const { enable, setVoter, setIsDrepLoading } = useCardano(); + const { enable } = useCardano(); const navigate = useNavigate(); - const { data } = useGetVoterInfo(); const { modal, openModal, modals } = useModal(); useWalletConnectionListener(); @@ -46,14 +45,6 @@ export default () => { SetupInterceptors(navigate); }, []); - useEffect(() => { - setIsDrepLoading(true); - setVoter(data); - const timer = setTimeout(() => setIsDrepLoading(false), 1000); - - return () => clearTimeout(timer); - }, [data?.isRegisteredAsDRep, data?.isRegisteredAsSoleVoter]); - const checkTheWalletIsActive = useCallback(() => { const hrefCondition = window.location.pathname === PATHS.home || @@ -135,8 +126,8 @@ export default () => { handleClose={ !modals[modal.type].preventDismiss ? callAll(modals[modal.type]?.onClose, () => - openModal({ type: "none", state: null }), - ) + openModal({ type: "none", state: null }), + ) : undefined } > diff --git a/govtool/frontend/src/components/atoms/VotingPowerChips.tsx b/govtool/frontend/src/components/atoms/VotingPowerChips.tsx index 56bd5625a..4e5381e56 100644 --- a/govtool/frontend/src/components/atoms/VotingPowerChips.tsx +++ b/govtool/frontend/src/components/atoms/VotingPowerChips.tsx @@ -6,31 +6,33 @@ import { useCardano } from "@context"; import { useGetAdaHolderVotingPowerQuery, useGetDRepVotingPowerQuery, + useGetVoterInfo, useScreenDimension, useTranslation, } from "@hooks"; import { correctAdaFormat } from "@utils"; export const VotingPowerChips = () => { - const { voter, stakeKey, isDrepLoading } = useCardano(); - const { dRepVotingPower, isDRepVotingPowerLoading } = - useGetDRepVotingPowerQuery(); - const { votingPower, powerIsLoading } = - useGetAdaHolderVotingPowerQuery(stakeKey); + const { stakeKey, isEnableLoading } = useCardano(); + const { dRepVotingPower } = useGetDRepVotingPowerQuery(); + const { votingPower } = useGetAdaHolderVotingPowerQuery(stakeKey); const { isMobile, screenWidth } = useScreenDimension(); const { t } = useTranslation(); + const { voter } = useGetVoterInfo(); return ( {voter?.isRegisteredAsDRep && ( { {t("votingPower")} )} - {(voter?.isRegisteredAsDRep && isDRepVotingPowerLoading) || - (!voter?.isRegisteredAsDRep && powerIsLoading) || - isDrepLoading ? ( - + {(voter?.isRegisteredAsDRep && dRepVotingPower === undefined) || + (!voter?.isRegisteredAsDRep && votingPower === undefined) || + isEnableLoading || + !voter ? ( + ) : ( (false); const { isMobile, screenWidth } = useScreenDimension(); const { openModal } = useModal(); - const { voter } = useCardano(); const { t } = useTranslation(); + const { voter } = useGetVoterInfo(); const { areFormErrors, @@ -74,28 +79,27 @@ export const VoteActionForm = ({ [state], ); - const renderChangeVoteButton = useMemo( - () => ( - - {t("govActions.changeVote")} - - ), + const renderChangeVoteButton = useMemo(() => ( + + {t('govActions.changeVote')} + + ), [confirmVote, areFormErrors, vote, isVoteLoading], ); @@ -247,16 +251,16 @@ export const VoteActionForm = ({ {t("govActions.selectDifferentOption")} {(state?.vote && state?.vote !== vote) || - (voteFromEP && voteFromEP !== vote) ? ( - - {isMobile ? renderChangeVoteButton : renderCancelButton} - - {isMobile ? renderCancelButton : renderChangeVoteButton} - + (voteFromEP && voteFromEP !== vote) ? ( + + {isMobile ? renderChangeVoteButton : renderCancelButton} + + {isMobile ? renderCancelButton : renderChangeVoteButton} + ) : ( { buildDRepRetirementCert, buildSignSubmitConwayCertTx, dRepID, + isEnableLoading, dRepIDBech32, - isDrepLoading, isPendingTransaction, pendingTransaction, stakeKey, - voter, } = useCardano(); const navigate = useNavigate(); const { currentDelegation } = @@ -36,16 +36,23 @@ export const DashboardCards = () => { const { votingPower } = useGetAdaHolderVotingPowerQuery(stakeKey); const { t } = useTranslation(); + const { voter } = useGetVoterInfo(); const retireAsDrep = useCallback(async () => { try { setIsRetirementLoading(true); const isPendingTx = isPendingTransaction(); + if (isPendingTx) return; - const certBuilder = await buildDRepRetirementCert(); + if (!voter?.deposit) throw new Error('Can not get deposit'); + + const certBuilder = await buildDRepRetirementCert( + voter.deposit.toString(), + ); const result = await buildSignSubmitConwayCertTx({ certBuilder, type: 'retireAsDrep', + voterDeposit: voter.deposit.toString(), }); if (result) { openModal({ @@ -82,6 +89,7 @@ export const DashboardCards = () => { buildSignSubmitConwayCertTx, isPendingTransaction, openModal, + voter?.deposit, ]); const delegationDescription = useMemo(() => { @@ -146,6 +154,7 @@ export const DashboardCards = () => { const correctAdaRepresentation = correctAdaFormat(votingPower); if (!pendingTransaction.delegate) return; const { resourceId } = pendingTransaction.delegate; + if (resourceId === dRepID) { return ( { ); const onClickGovernanceActionCardActionButton = useCallback(() => { - if (!pendingTransaction.createGovAction) { + if (pendingTransaction.createGovAction) { navigate(PATHS.dashboardGovernanceActions); return; } navigate(PATHS.createGovernanceAction); - }, [pendingTransaction, navigate]); + }, [pendingTransaction.createGovAction, navigate]); const displayedDelegationId = useMemo(() => { const restrictedNames = [ @@ -286,7 +295,7 @@ export const DashboardCards = () => { voter?.isRegisteredAsSoleVoter, ]); - return isDrepLoading ? ( + return isEnableLoading || !currentDelegation || !voter || !votingPower ? ( { const { screenWidth } = useScreenDimension(); - const { voter } = useCardano(); + const { voter } = useGetVoterInfo(); const openDrawer = () => { setIsDrawerOpen(true); diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx index df382e1f6..586005b07 100644 --- a/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx +++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx @@ -14,9 +14,9 @@ import { } from "@mui/material"; import { ICONS, PATHS } from "@consts"; -import { useCardano } from "@context"; import { useGetProposalQuery, + useGetVoterInfo, useScreenDimension, useTranslation, } from "@hooks"; @@ -28,7 +28,7 @@ import { } from "@utils"; export const DashboardGovernanceActionDetails = () => { - const { voter } = useCardano(); + const { voter } = useGetVoterInfo(); const { state, hash } = useLocation(); const navigate = useNavigate(); const { isMobile, screenWidth } = useScreenDimension(); diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx index 59389f6d3..d865e5e8d 100644 --- a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx +++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx @@ -2,13 +2,19 @@ import { useState, useCallback, useEffect } from "react"; import { Box, CircularProgress, Tab, Tabs, styled } from "@mui/material"; import { useLocation } from "react-router-dom"; -import { useCardano } from "@context"; -import { useScreenDimension, useTranslation } from "@hooks"; -import { DataActionsBar } from "@molecules"; +import { GOVERNANCE_ACTIONS_FILTERS } from '@consts'; +import { useCardano } from '@context'; +import { + useGetProposalsQuery, + useGetVoterInfo, + useScreenDimension, + useTranslation, +} from '@hooks'; +import { DataActionsBar } from '@molecules'; import { GovernanceActionsToVote, DashboardGovernanceActionsVotedOn, -} from "@organisms"; +} from '@organisms'; interface TabPanelProps { children?: React.ReactNode; @@ -16,6 +22,10 @@ interface TabPanelProps { value: number; } +const defaultCategories = GOVERNANCE_ACTIONS_FILTERS.map( + (category) => category.key, +); + const CustomTabPanel = (props: TabPanelProps) => { const { children, value, index } = props; @@ -26,8 +36,8 @@ const CustomTabPanel = (props: TabPanelProps) => { id={`simple-tabpanel-${index}`} aria-labelledby={`simple-tab-${index}`} style={{ - display: "flex", - flexDirection: "column", + display: 'flex', + flexDirection: 'column', flex: value !== index ? 0 : 1, }} > @@ -43,32 +53,41 @@ type StyledTabProps = { const StyledTab = styled((props: StyledTabProps) => ( ))(() => ({ - textTransform: "none", + textTransform: 'none', fontWeight: 400, fontSize: 16, - color: "#242232", - "&.Mui-selected": { - color: "#FF640A", + color: '#242232', + '&.Mui-selected': { + color: '#FF640A', fontWeight: 500, }, })); export const DashboardGovernanceActions = () => { - const [searchText, setSearchText] = useState(""); + const [searchText, setSearchText] = useState(''); const [filtersOpen, setFiltersOpen] = useState(false); const [chosenFilters, setChosenFilters] = useState([]); const [sortOpen, setSortOpen] = useState(false); - const [chosenSorting, setChosenSorting] = useState(""); + const [chosenSorting, setChosenSorting] = useState(''); + const { voter } = useGetVoterInfo(); + const { isMobile } = useScreenDimension(); + const { t } = useTranslation(); + const { isEnableLoading } = useCardano(); + + const queryFilters = + chosenFilters.length > 0 ? chosenFilters : defaultCategories; + + const { proposals, isProposalsLoading } = useGetProposalsQuery({ + filters: queryFilters, + sorting: chosenSorting, + searchPhrase: searchText, + }); const { state } = useLocation(); const [content, setContent] = useState( state && state.isVotedListOnLoad ? 1 : 0, ); - const { voter, isDrepLoading } = useCardano(); - const { isMobile } = useScreenDimension(); - const { t } = useTranslation(); - const handleChange = (_event: React.SyntheticEvent, newValue: number) => { setContent(newValue); }; @@ -93,83 +112,86 @@ export const DashboardGovernanceActions = () => { display="flex" flexDirection="column" > - {isDrepLoading ? ( - - - - ) : ( - <> - - {(voter?.isRegisteredAsDRep || voter?.isRegisteredAsSoleVoter) && ( - - + + {!proposals || !voter || isEnableLoading || isProposalsLoading ? ( + + + + ) : ( + <> + {(voter?.isRegisteredAsDRep || voter?.isRegisteredAsSoleVoter) && ( + + + + + )} + + + - + + - - )} - - - - - - - - - )} + + + )} + ); }; diff --git a/govtool/frontend/src/components/organisms/DelegateTodRepStepOne.tsx b/govtool/frontend/src/components/organisms/DelegateTodRepStepOne.tsx index 61a5d355c..6524497d4 100644 --- a/govtool/frontend/src/components/organisms/DelegateTodRepStepOne.tsx +++ b/govtool/frontend/src/components/organisms/DelegateTodRepStepOne.tsx @@ -8,6 +8,7 @@ import { useCardano, useModal } from "@context"; import { useGetAdaHolderCurrentDelegationQuery, useGetAdaHolderVotingPowerQuery, + useGetVoterInfo, useScreenDimension, useTranslation, } from "@hooks"; @@ -21,12 +22,12 @@ interface DelegateProps { export const DelegateTodRepStepOne = ({ setStep }: DelegateProps) => { const navigate = useNavigate(); const { - voter, dRepID, buildSignSubmitConwayCertTx, buildVoteDelegationCert, stakeKey, } = useCardano(); + const { voter } = useGetVoterInfo(); const { currentDelegation } = useGetAdaHolderCurrentDelegationQuery(stakeKey); const { openModal, closeModal } = useModal(); const [areOptions, setAreOptions] = useState(false); diff --git a/govtool/frontend/src/components/organisms/Drawer.tsx b/govtool/frontend/src/components/organisms/Drawer.tsx index cc790ae80..b69c1dd51 100644 --- a/govtool/frontend/src/components/organisms/Drawer.tsx +++ b/govtool/frontend/src/components/organisms/Drawer.tsx @@ -1,39 +1,38 @@ -import { Box, Grid } from "@mui/material"; -import { NavLink } from "react-router-dom"; +import { Box, Grid } from '@mui/material'; +import { NavLink } from 'react-router-dom'; import { DrawerLink, Typography } from "@atoms"; import { CONNECTED_NAV_ITEMS, ICONS, IMAGES, PATHS } from "@consts"; -import { useCardano } from "@context"; -import { useTranslation } from "@hooks"; +import { useGetVoterInfo, useTranslation } from "@hooks"; import { WalletInfoCard, DRepInfoCard } from "@molecules"; import { openInNewTab } from "@utils"; export const Drawer = () => { - const { voter } = useCardano(); + const { voter } = useGetVoterInfo(); const { t } = useTranslation(); return ( app-logo { { /> - {t("footer.copyright")} + {t('footer.copyright')} diff --git a/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx b/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx index b4535880a..41eaa2bb2 100644 --- a/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx +++ b/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx @@ -1,35 +1,28 @@ /* eslint-disable no-unsafe-optional-chaining */ -import { useMemo } from "react"; import { useNavigate, generatePath } from "react-router-dom"; -import { Box, CircularProgress } from "@mui/material"; +import { Box } from "@mui/material"; import { Typography } from '@atoms'; -import { - useGetProposalsQuery, - useScreenDimension, - useTranslation, -} from '@hooks'; -import { GovernanceActionCard } from '@molecules'; -import { GOVERNANCE_ACTIONS_FILTERS, PATHS } from '@consts'; +import { PATHS } from '@consts'; import { useCardano } from '@context'; +import { useScreenDimension, useTranslation } from '@hooks'; +import { GovernanceActionCard } from '@molecules'; import { getProposalTypeLabel, getFullGovActionId, openInNewTab } from '@utils'; import { Slider } from './Slider'; type GovernanceActionsToVoteProps = { filters: string[]; + sorting: string; + proposals: { title: string; actions: ActionType[] }[]; onDashboard?: boolean; searchPhrase?: string; - sorting: string; }; -const defaultCategories = GOVERNANCE_ACTIONS_FILTERS.map( - (category) => category.key, -); - export const GovernanceActionsToVote = ({ filters, onDashboard = true, - searchPhrase = '', + proposals, + searchPhrase, sorting, }: GovernanceActionsToVoteProps) => { const { pendingTransaction } = useCardano(); @@ -37,55 +30,15 @@ export const GovernanceActionsToVote = ({ const { isMobile } = useScreenDimension(); const { t } = useTranslation(); - const queryFilters = filters.length > 0 ? filters : defaultCategories; - - const { proposals, isProposalsLoading } = useGetProposalsQuery({ - filters: queryFilters, - sorting, - }); - - const groupedByType = (data?: ActionType[]) => - data?.reduce((groups, item) => { - const itemType = item.type; - - // TODO: Provide better typing for groups - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - if (!groups[itemType]) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - groups[itemType] = { - title: itemType, - actions: [], - }; - } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - groups[itemType].actions.push(item); - - return groups; - }, {}); - - const mappedData = useMemo(() => { - const groupedData = groupedByType( - proposals?.filter((i) => - getFullGovActionId(i.txHash, i.index) - .toLowerCase() - .includes(searchPhrase.toLowerCase()), - ), - ); - return Object.values(groupedData ?? []) as ToVoteDataType; - }, [proposals, searchPhrase]); - - return !isProposalsLoading ? ( + return ( <> - {!mappedData.length ? ( + {!proposals.length ? ( {t('govActions.noResultsForTheSearch')} ) : ( <> - {mappedData?.map((item, index) => ( + {proposals?.map((item, index) => ( ( @@ -149,7 +102,7 @@ export const GovernanceActionsToVote = ({ sorting={sorting} title={getProposalTypeLabel(item.title)} /> - {index < mappedData.length - 1 && ( + {index < proposals.length - 1 && ( )} @@ -157,15 +110,5 @@ export const GovernanceActionsToVote = ({ )} - ) : ( - - - ); }; diff --git a/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBox.tsx b/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBox.tsx index ac825fabc..445b0a474 100644 --- a/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBox.tsx +++ b/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBox.tsx @@ -6,19 +6,17 @@ import { PATHS } from "@consts"; import { RegisterAsSoleVoterBoxContent } from "@organisms"; import { CenteredBoxBottomButtons } from "@molecules"; import { useCardano, useModal } from "@context"; +import { useGetVoterInfo } from "@/hooks"; export const RegisterAsSoleVoterBox = () => { const [isLoading, setIsLoading] = useState(false); - const { - buildSignSubmitConwayCertTx, - buildDRepRegCert, - buildDRepUpdateCert, - voter, - } = useCardano(); + const { buildSignSubmitConwayCertTx, buildDRepRegCert, buildDRepUpdateCert } = + useCardano(); const navigate = useNavigate(); const { openModal, closeModal } = useModal(); const { t } = useTranslation(); + const { voter } = useGetVoterInfo(); const onRegister = useCallback(async () => { setIsLoading(true); diff --git a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx index 666fc06f6..f691d3d72 100644 --- a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx +++ b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx @@ -6,6 +6,7 @@ import { PATHS } from "@consts"; import { CenteredBoxBottomButtons } from "@molecules"; import { useCardano, useModal } from "@context"; import { RetireAsSoleVoterBoxContent } from "@organisms"; +import { useGetVoterInfo } from "@/hooks"; export const RetireAsSoleVoterBox = () => { const [isLoading, setIsLoading] = useState(false); @@ -18,16 +19,23 @@ export const RetireAsSoleVoterBox = () => { } = useCardano(); const { openModal, closeModal } = useModal(); const { t } = useTranslation(); + const { voter } = useGetVoterInfo(); const onRetire = useCallback(async () => { try { setIsLoading(true); const isPendingTx = isPendingTransaction(); if (isPendingTx) return; - const certBuilder = await buildDRepRetirementCert(); + if (!voter?.deposit) { + throw new Error("Can not fetch deposit"); + } + const certBuilder = await buildDRepRetirementCert( + voter?.deposit?.toString() + ); const result = await buildSignSubmitConwayCertTx({ certBuilder, type: "retireAsSoleVoter", + voterDeposit: voter?.deposit?.toString(), }); if (result) { openModal({ @@ -72,6 +80,7 @@ export const RetireAsSoleVoterBox = () => { buildSignSubmitConwayCertTx, isPendingTransaction, openModal, + voter?.deposit, ]); return ( diff --git a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx index bb371f0c4..983e0b81d 100644 --- a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx +++ b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx @@ -2,14 +2,13 @@ import { Link } from "@mui/material"; import { Trans } from "react-i18next"; import { Typography } from "@atoms"; -import { useScreenDimension, useTranslation } from "@hooks"; -import { correctAdaFormat, openInNewTab } from "@/utils"; -import { useCardano } from "@/context"; +import { useGetVoterInfo, useScreenDimension, useTranslation } from "@hooks"; +import { correctAdaFormat, openInNewTab } from "@utils"; export const RetireAsSoleVoterBoxContent = () => { const { isMobile } = useScreenDimension(); const { t } = useTranslation(); - const { voter } = useCardano(); + const { voter } = useGetVoterInfo(); return ( <> diff --git a/govtool/frontend/src/components/organisms/Slider.tsx b/govtool/frontend/src/components/organisms/Slider.tsx index 6bc159e14..577ca56a6 100644 --- a/govtool/frontend/src/components/organisms/Slider.tsx +++ b/govtool/frontend/src/components/organisms/Slider.tsx @@ -38,7 +38,7 @@ export const Slider = ({ }: SliderProps) => { const { isMobile, screenWidth, pagePadding } = useScreenDimension(); const navigate = useNavigate(); - const { voteTransaction } = useCardano(); + const { pendingTransaction } = useCardano(); const { t } = useTranslation(); const DEFAULT_SLIDER_CONFIG = { @@ -75,7 +75,7 @@ export const Slider = ({ useEffect(() => { refresh(); - }, [filters, sorting, searchPhrase, voteTransaction?.proposalId, data]); + }, [filters, sorting, searchPhrase, pendingTransaction.vote?.resourceId, data]); const rangeSliderCalculationElement = dataLength < notSlicedDataLength diff --git a/govtool/frontend/src/context/getUtxos.ts b/govtool/frontend/src/context/getUtxos.ts index 0ae7c219b..23fc0a198 100644 --- a/govtool/frontend/src/context/getUtxos.ts +++ b/govtool/frontend/src/context/getUtxos.ts @@ -50,6 +50,8 @@ export const getUtxos = async ( for (let j = 0; j < K; j++) { const assetName = assetNames.get(j); const assetNameString = assetName.name().toString(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const assetNameHex = Buffer.from( assetName.name(), "utf8" @@ -75,6 +77,7 @@ export const getUtxos = async ( return utxos; } catch (err) { Sentry.captureException(err); + // eslint-disable-next-line no-console console.error(err); } }; diff --git a/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts b/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts index 14ef13629..18f1e4a7c 100644 --- a/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts +++ b/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts @@ -26,9 +26,9 @@ type UsePendingTransactionProps = { }; export const usePendingTransaction = ({ - dRepID, isEnabled, stakeKey, + dRepID, }: UsePendingTransactionProps) => { const { t } = useTranslation(); const { openModal, closeModal } = useModal(); @@ -163,4 +163,4 @@ export const usePendingTransaction = ({ }; const isTransactionExpired = (time: Date): boolean => - new Date().getTime() - time.getTime() > TIME_TO_EXPIRE_TRANSACTION; + Date.now() - time.getTime() > TIME_TO_EXPIRE_TRANSACTION; diff --git a/govtool/frontend/src/context/wallet.tsx b/govtool/frontend/src/context/wallet.tsx index 9f2b0dbc9..75eb48eb0 100644 --- a/govtool/frontend/src/context/wallet.tsx +++ b/govtool/frontend/src/context/wallet.tsx @@ -2,8 +2,6 @@ /* eslint-disable */ // @ts-nocheck import { - Dispatch, - SetStateAction, createContext, useCallback, useContext, @@ -53,7 +51,7 @@ import * as Sentry from '@sentry/react'; import { Trans } from 'react-i18next'; import { PATHS } from '@consts'; -import { CardanoApiWallet, VoterInfo, Protocol } from '@models'; +import { CardanoApiWallet, Protocol } from '@models'; import type { StatusModalState } from '@organisms'; import { checkIsMaintenanceOn, @@ -105,31 +103,29 @@ interface CardanoContext { enable: (walletName: string) => Promise; isEnableLoading: string | null; error?: string; - voter: VoterInfo | undefined; isEnabled: boolean; pubDRepKey: string; dRepID: string; dRepIDBech32: string; isMainnet: boolean; stakeKey?: string; - setVoter: (key: undefined | VoterInfo) => void; setStakeKey: (key: string) => void; stakeKeys: string[]; walletApi?: CardanoApiWallet; - delegatedDRepID?: string; - setDelegatedDRepID: (key: string) => void; buildSignSubmitConwayCertTx: ({ certBuilder, govActionBuilder, resourceId, type, votingBuilder, + voterDeposit, }: { certBuilder?: CertificatesBuilder; govActionBuilder?: VotingProposalBuilder; resourceId?: string; type: TransactionType; votingBuilder?: VotingBuilder; + voterDeposit?: string; }) => Promise; buildDRepRegCert: ( url?: string, @@ -142,7 +138,9 @@ interface CardanoContext { hash?: string, hash?: string, ) => Promise; - buildDRepRetirementCert: () => Promise; + buildDRepRetirementCert: ( + voterDeposit: string, + ) => Promise; buildVote: ( voteChoice: string, txHash: string, @@ -153,8 +151,6 @@ interface CardanoContext { ) => Promise; pendingTransaction: PendingTransaction; isPendingTransaction: () => boolean; - isDrepLoading: boolean; - setIsDrepLoading: Dispatch>; buildNewInfoGovernanceAction: ( infoProps: InfoProps, ) => Promise; @@ -180,7 +176,6 @@ CardanoContext.displayName = 'CardanoContext'; const CardanoProvider = (props: Props) => { const [isEnabled, setIsEnabled] = useState(false); const [isEnableLoading, setIsEnableLoading] = useState(null); - const [voter, setVoter] = useState(undefined); const [walletApi, setWalletApi] = useState( undefined, ); @@ -195,9 +190,6 @@ const CardanoProvider = (props: Props) => { const [registeredStakeKeysListState, setRegisteredPubStakeKeysState] = useState([]); const [error, setError] = useState(undefined); - const [delegatedDRepID, setDelegatedDRepID] = useState( - undefined, - ); const [walletState, setWalletState] = useState<{ changeAddress: undefined | string; usedAddress: undefined | string; @@ -205,7 +197,6 @@ const CardanoProvider = (props: Props) => { changeAddress: undefined, usedAddress: undefined, }); - const [isDrepLoading, setIsDrepLoading] = useState(true); const { t } = useTranslation(); const epochParams = getItemFromLocalStorage(PROTOCOL_PARAMS_KEY); @@ -221,7 +212,7 @@ const CardanoProvider = (props: Props) => { setWalletState((prev) => ({ ...prev, changeAddress })); } catch (err) { Sentry.captureException(err); - console.log(err); + console.error(err); } }; @@ -235,7 +226,7 @@ const CardanoProvider = (props: Props) => { setWalletState((prev) => ({ ...prev, usedAddress })); } catch (err) { Sentry.captureException(err); - console.log(err); + console.error(err); } }; @@ -438,12 +429,14 @@ const CardanoProvider = (props: Props) => { resourceId, type, votingBuilder, + voterDeposit, }: { certBuilder?: CertificatesBuilder; govActionBuilder?: VotingProposalBuilder; resourceId?: string; type: TransactionType; votingBuilder?: VotingBuilder; + voterDeposit?: string; }) => { await checkIsMaintenanceOn(); const isPendingTx = isPendingTransaction(); @@ -486,11 +479,9 @@ const CardanoProvider = (props: Props) => { if ( (type === 'retireAsDrep' || type === 'retireAsSoleVoter') && - voter?.deposit + voterDeposit ) { - outputValue = outputValue.checked_add( - BigNum.from_str(`${voter?.deposit}`), - ); + outputValue = outputValue.checked_add(BigNum.from_str(voterDeposit)); } txBuilder.add_output( @@ -564,14 +555,7 @@ const CardanoProvider = (props: Props) => { throw error?.info ?? error; } }, - [ - isPendingTransaction, - stakeKey, - updateTransaction, - voter?.deposit, - walletApi, - walletState, - ], + [isPendingTransaction, stakeKey, updateTransaction, walletApi, walletState], ); const buildVoteDelegationCert = useCallback( @@ -699,8 +683,8 @@ const CardanoProvider = (props: Props) => { ); // conway alpha - const buildDRepRetirementCert = - useCallback(async (): Promise => { + const buildDRepRetirementCert = useCallback( + async (voterDeposit: string): Promise => { try { // Build DRep Registration Certificate const certBuilder = CertificatesBuilder.new(); @@ -710,7 +694,7 @@ const CardanoProvider = (props: Props) => { const dRepRetirementCert = DrepDeregistration.new( dRepCred, - BigNum.from_str(`${voter?.deposit}`), + BigNum.from_str(voterDeposit), ); // add cert to tbuilder certBuilder.add( @@ -722,7 +706,9 @@ const CardanoProvider = (props: Props) => { console.log(e); throw e; } - }, [dRepID, voter]); + }, + [dRepID], + ); const buildVote = useCallback( async ( @@ -873,26 +859,20 @@ const CardanoProvider = (props: Props) => { buildTreasuryGovernanceAction, buildVote, buildVoteDelegationCert, - delegatedDRepID, disconnectWallet, dRepID, dRepIDBech32, enable, error, - isDrepLoading, isEnabled, isEnableLoading, isMainnet, isPendingTransaction, pendingTransaction, pubDRepKey, - setDelegatedDRepID, - setIsDrepLoading, setStakeKey, - setVoter, stakeKey, stakeKeys, - voter, walletApi, }), [ @@ -905,26 +885,20 @@ const CardanoProvider = (props: Props) => { buildTreasuryGovernanceAction, buildVote, buildVoteDelegationCert, - delegatedDRepID, disconnectWallet, dRepID, dRepIDBech32, enable, error, - isDrepLoading, isEnabled, isEnableLoading, isMainnet, isPendingTransaction, pendingTransaction, pubDRepKey, - setDelegatedDRepID, - setIsDrepLoading, setStakeKey, - setVoter, stakeKey, stakeKeys, - voter, walletApi, ], ); diff --git a/govtool/frontend/src/hooks/forms/useDelegateTodRepForm.tsx b/govtool/frontend/src/hooks/forms/useDelegateTodRepForm.tsx index 1878b33d7..12794fd79 100644 --- a/govtool/frontend/src/hooks/forms/useDelegateTodRepForm.tsx +++ b/govtool/frontend/src/hooks/forms/useDelegateTodRepForm.tsx @@ -12,11 +12,7 @@ export interface DelegateTodrepFormValues { } export const useDelegateTodRepForm = () => { - const { - setDelegatedDRepID, - buildSignSubmitConwayCertTx, - buildVoteDelegationCert, - } = useCardano(); + const { buildSignSubmitConwayCertTx, buildVoteDelegationCert } = useCardano(); const { data: drepList } = useGetDRepListQuery(); const { openModal, closeModal, modal } = useModal(); const [isLoading, setIsLoading] = useState(false); @@ -40,7 +36,6 @@ export const useDelegateTodRepForm = () => { async ({ dRepID }: DelegateTodrepFormValues) => { setIsLoading(true); try { - setDelegatedDRepID(dRepID); let isValidDrep = false; if (drepList?.length) { isValidDrep = drepList.some( diff --git a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts index 22185f4b7..03247b518 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts @@ -3,9 +3,11 @@ import { useQuery } from "react-query"; import { QUERY_KEYS } from "@consts"; import { useCardano } from "@context"; import { getDRepVotingPower } from "@services"; +import { useGetVoterInfo } from "."; export const useGetDRepVotingPowerQuery = () => { - const { dRepID, voter } = useCardano(); + const { dRepID } = useCardano(); + const { voter } = useGetVoterInfo(); const { data, isLoading } = useQuery({ queryKey: [ diff --git a/govtool/frontend/src/hooks/queries/useGetProposalsQuery.ts b/govtool/frontend/src/hooks/queries/useGetProposalsQuery.ts index 6ba2e581a..3d0434acd 100644 --- a/govtool/frontend/src/hooks/queries/useGetProposalsQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetProposalsQuery.ts @@ -3,12 +3,14 @@ import { useQuery } from "react-query"; import { QUERY_KEYS } from "@consts"; import { useCardano } from "@context"; import { getProposals, getProposalsArguments } from "@services"; +import { getFullGovActionId } from "@utils"; export const useGetProposalsQuery = ({ filters = [], sorting, + searchPhrase, }: getProposalsArguments) => { - const { dRepID, isEnabled, pendingTransaction } = useCardano(); + const { dRepID, pendingTransaction } = useCardano(); const fetchProposals = async (): Promise => { const allProposals = await Promise.all( @@ -25,15 +27,44 @@ export const useGetProposalsQuery = ({ QUERY_KEYS.useGetProposalsKey, filters, sorting, - isEnabled, dRepID, pendingTransaction.vote, ], fetchProposals, ); + const mappedData = Object.values( + (groupedByType( + data?.filter((i) => + getFullGovActionId(i.txHash, i.index) + .toLowerCase() + .includes(searchPhrase.toLowerCase())) + ) ?? []) as ToVoteDataType + ); + return { isProposalsLoading: isLoading, - proposals: data, + proposals: mappedData, }; }; + +const groupedByType = (data?: ActionType[]) => data?.reduce((groups, item) => { + const itemType = item.type; + + // TODO: Provide better typing for groups + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + if (!groups[itemType]) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + groups[itemType] = { + title: itemType, + actions: [], + }; + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + groups[itemType].actions.push(item); + + return groups; +}, {}); diff --git a/govtool/frontend/src/hooks/queries/useGetVoterInfoQuery.ts b/govtool/frontend/src/hooks/queries/useGetVoterInfoQuery.ts index 44a3c15d3..5eab75e42 100644 --- a/govtool/frontend/src/hooks/queries/useGetVoterInfoQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetVoterInfoQuery.ts @@ -7,7 +7,7 @@ import { getVoterInfo } from "@services"; export const useGetVoterInfo = () => { const { dRepID, pendingTransaction } = useCardano(); - const { data, isLoading } = useQuery({ + const { data } = useQuery({ queryKey: [ QUERY_KEYS.useGetDRepInfoKey, pendingTransaction.registerAsDrep || @@ -19,5 +19,5 @@ export const useGetVoterInfo = () => { queryFn: () => getVoterInfo(dRepID), }); - return { data, isLoading }; + return { voter: data }; }; diff --git a/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx b/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx index d54896e55..8685bfbf8 100644 --- a/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx +++ b/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx @@ -20,6 +20,7 @@ import { DataActionsBar, GovernanceActionCard } from "@molecules"; import { useFetchNextPageDetector, useGetProposalsInfiniteQuery, + useGetVoterInfo, useSaveScrollPosition, useScreenDimension, useTranslation, @@ -38,7 +39,8 @@ export const DashboardGovernanceActionsCategory = () => { const [chosenSorting, setChosenSorting] = useState(""); const { isMobile, screenWidth } = useScreenDimension(); const navigate = useNavigate(); - const { voter, isDrepLoading, voteTransaction } = useCardano(); + const { pendingTransaction, isEnableLoading } = useCardano(); + const { voter } = useGetVoterInfo(); const { t } = useTranslation(); const { @@ -51,6 +53,7 @@ export const DashboardGovernanceActionsCategory = () => { } = useGetProposalsInfiniteQuery({ filters: [category?.replace(/ /g, "") ?? ""], sorting: chosenSorting, + searchPhrase: searchText, }); const loadNextPageRef = useRef(null); @@ -150,7 +153,7 @@ export const DashboardGovernanceActionsCategory = () => { sortOpen={sortOpen} /> - {isProposalsLoading || isDrepLoading ? ( + {!mappedData || isEnableLoading || isProposalsLoading ? ( @@ -172,13 +175,12 @@ export const DashboardGovernanceActionsCategory = () => { {mappedData.map((item) => ( @@ -186,33 +188,34 @@ export const DashboardGovernanceActionsCategory = () => { {...item} index={item.index} inProgress={ - voteTransaction.proposalId === item.txHash + item.index + pendingTransaction.vote?.resourceId === + item.txHash + item.index } onClick={() => { saveScrollPosition(); // eslint-disable-next-line no-unused-expressions - voteTransaction.proposalId === item.txHash + item.index + pendingTransaction.vote?.resourceId === item.txHash + item.index ? openInNewTab( - "https://adanordic.com/latest_transactions", - ) + "https://adanordic.com/latest_transactions", + ) : navigate( - generatePath( - PATHS.dashboardGovernanceActionsAction, - { - proposalId: getFullGovActionId( - item.txHash, - item.index, - ), - }, - ), + generatePath( + PATHS.dashboardGovernanceActionsAction, { - state: { - ...item, - openedFromCategoryPage: true, - }, + proposalId: getFullGovActionId( + item.txHash, + item.index, + ), }, - ); + ), + { + state: { + ...item, + openedFromCategoryPage: true, + }, + }, + ); }} txHash={item.txHash} /> diff --git a/govtool/frontend/src/pages/GovernanceActions.tsx b/govtool/frontend/src/pages/GovernanceActions.tsx index 2867a6ccf..08eb11d15 100644 --- a/govtool/frontend/src/pages/GovernanceActions.tsx +++ b/govtool/frontend/src/pages/GovernanceActions.tsx @@ -1,15 +1,23 @@ import { useState, useCallback, useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import { Box, Divider } from "@mui/material"; +import { Box, CircularProgress, Divider } from "@mui/material"; import { Background, ScrollToManage, Typography } from "@atoms"; -import { PATHS } from "@consts"; +import { GOVERNANCE_ACTIONS_FILTERS, PATHS } from "@consts"; import { useCardano } from "@context"; -import { useScreenDimension, useTranslation } from "@hooks"; +import { + useGetProposalsQuery, + useScreenDimension, + useTranslation, +} from "@hooks"; import { DataActionsBar } from "@molecules"; import { Footer, TopNav, GovernanceActionsToVote } from "@organisms"; import { WALLET_LS_KEY, getItemFromLocalStorage } from "@utils"; +const defaultCategories = GOVERNANCE_ACTIONS_FILTERS.map( + (category) => category.key +); + export const GovernanceActions = () => { const [searchText, setSearchText] = useState(""); const [filtersOpen, setFiltersOpen] = useState(false); @@ -21,6 +29,15 @@ export const GovernanceActions = () => { const navigate = useNavigate(); const { t } = useTranslation(); + const queryFilters = + chosenFilters.length > 0 ? chosenFilters : defaultCategories; + + const { proposals, isProposalsLoading } = useGetProposalsQuery({ + filters: queryFilters, + sorting: chosenSorting, + searchPhrase: searchText, + }); + useEffect(() => { if (isEnabled && getItemFromLocalStorage(`${WALLET_LS_KEY}_stake_key`)) { navigate(PATHS.dashboardGovernanceActions); @@ -79,12 +96,25 @@ export const GovernanceActions = () => { sortOpen={sortOpen} /> - + {!proposals || isProposalsLoading ? ( + + + + ) : ( + + )}