From b022a3c64c1039db1e81f0ea6eadbaa8a248e95c Mon Sep 17 00:00:00 2001 From: Uncle Fatso Date: Tue, 28 Apr 2026 15:06:12 +0300 Subject: [PATCH] make all actionable buttons to show loading state with appropriate text Signed-off-by: Uncle Fatso --- package.json | 2 +- src/containers/Bond/components/ClaimBonds.jsx | 9 +++- src/containers/Breakout/BreakoutModal.jsx | 6 ++- src/containers/Bridge/BridgeCard.jsx | 2 +- src/containers/Dex/PoolContainer.jsx | 4 +- src/containers/Dex/SwapContainer.jsx | 6 ++- src/containers/Governance/NewProposal.jsx | 1 + src/containers/Governance/ProposalDetails.jsx | 49 ++++++++++++++----- 8 files changed, 58 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 373578c..36314ab 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ghost-dao-interface", "private": true, - "version": "0.7.29", + "version": "0.7.30", "type": "module", "scripts": { "dev": "vite", diff --git a/src/containers/Bond/components/ClaimBonds.jsx b/src/containers/Bond/components/ClaimBonds.jsx index 0e3eeb3..70aca91 100644 --- a/src/containers/Bond/components/ClaimBonds.jsx +++ b/src/containers/Bond/components/ClaimBonds.jsx @@ -27,6 +27,7 @@ import { useBreakoutModal } from "../../../hooks/breakoutModal"; export const ClaimBonds = ({ chainId, address, secondsTo }) => { const isSmallScreen = useScreenSize("md"); const [isPending, setIsPending] = useState(false); + const [pendingIndexes, setPendingIndexes] = useState([]); const [isWarmup, setIsWapmup] = useState(false); const [isPreClaimConfirmed, setPreClaimConfirmed] = useState(false); const [isPayoutGhst, _] = useState(true); @@ -55,6 +56,7 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => { const onSubmit = async (indexes) => { setIsPending(true); + setPendingIndexes(indexes); const defaultFunction = async () => { await redeem({ chainId, user: address, isGhst: isPayoutGhst, indexes }); @@ -82,6 +84,7 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => { breakoutFromBonding({ defaultFunction, toExecute, amount, warmupLeft }) } + setPendingIndexes([]); setIsPending(false); } @@ -177,9 +180,10 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => { onSubmit([note.id])} > - Claim + {isPending && pendingIndexes.includes(note.id) ? "Claiming" : "Claim"} @@ -236,9 +240,10 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => { onSubmit([note.id])} > - Claim + {isPending && pendingIndexes.includes(note.id) ? "Claiming" : "Claim"} diff --git a/src/containers/Breakout/BreakoutModal.jsx b/src/containers/Breakout/BreakoutModal.jsx index dc28c64..da586c9 100644 --- a/src/containers/Breakout/BreakoutModal.jsx +++ b/src/containers/Breakout/BreakoutModal.jsx @@ -278,9 +278,10 @@ const WelcomeView = ({ {warmupPeriod <= 0 && callDefaultFunction()} disabled={isPending || warmupPeriod > 0} + loading={isPending} fullWidth > - Claim {isStakingOpened ? "(3, 3) Stake" : "(1, 1) Bond"} + {isPending ? "Claiming..." : `Claim ${isStakingOpened ? "(3, 3) Stake" : "(1, 1) Bond"}`} } @@ -463,10 +464,11 @@ const ConfirmStep = ({ execute()} + loading={isPending} disabled={isPending || !acknowledgeWalletCustody || !acknowledgeBridgingRisk} fullWidth > - I Confirm + {isPending ? "Confirming..." : "I Confirm"} ) diff --git a/src/containers/Bridge/BridgeCard.jsx b/src/containers/Bridge/BridgeCard.jsx index 458b154..665ba71 100644 --- a/src/containers/Bridge/BridgeCard.jsx +++ b/src/containers/Bridge/BridgeCard.jsx @@ -246,7 +246,7 @@ export const BridgeCardAction = ({ loading={isPending} onClick={() => ghostOrConnect()} > - {address === "" ? "Connect" : "Bridge" } + {address === "" ? "Connect" : isPending ? "Bridging..." : "Bridge" } ) diff --git a/src/containers/Dex/PoolContainer.jsx b/src/containers/Dex/PoolContainer.jsx index 6e3a2ac..de54cc2 100644 --- a/src/containers/Dex/PoolContainer.jsx +++ b/src/containers/Dex/PoolContainer.jsx @@ -317,9 +317,9 @@ const PoolContainer = ({ "Connect" : pairAddress === "0x0000000000000000000000000000000000000000" ? - "Create Pool" + isPending ? "Creating Pool..." : "Create Pool" : - "Add Liquidity" + isPending ? "Adding Liquidity..." : "Add Liquidity" } diff --git a/src/containers/Dex/SwapContainer.jsx b/src/containers/Dex/SwapContainer.jsx index cdb31e4..ed67845 100644 --- a/src/containers/Dex/SwapContainer.jsx +++ b/src/containers/Dex/SwapContainer.jsx @@ -147,8 +147,12 @@ const SwapContainer = ({ if (isWrapping) text = "Wrap"; else if (isUnwrapping) text = "Unwrap"; else if (pairAddress === EMPTY_ADDRESS) text = "Create Pool"; + + if (isPending) text = `${text}ping...` + if (pairAddress === EMPTY_ADDRESS && isPending) text = "Creating Pool..." + return text; - }, [isWrapping, isUnwrapping, pairAddress]); + }, [isPending, isWrapping, isUnwrapping, pairAddress]); const swapTokens = async () => { setIsPending(true); diff --git a/src/containers/Governance/NewProposal.jsx b/src/containers/Governance/NewProposal.jsx index 62c0201..ad2716c 100644 --- a/src/containers/Governance/NewProposal.jsx +++ b/src/containers/Governance/NewProposal.jsx @@ -178,6 +178,7 @@ const NewProposal = ({ config, address, connect, chainId }) => { isPending } fullWidth + loading={isPending} onClick={() => submitProposal()} > {isPending ? "Submitting..." : "Submit Proposal"} diff --git a/src/containers/Governance/ProposalDetails.jsx b/src/containers/Governance/ProposalDetails.jsx index d33b212..750ff8d 100644 --- a/src/containers/Governance/ProposalDetails.jsx +++ b/src/containers/Governance/ProposalDetails.jsx @@ -80,7 +80,9 @@ const ProposalDetails = ({ chainId, address, connect, config }) => { const { id } = useParams(); const proposalId = BigInt(id); - const [isPending, setIsPending] = useState(false); + const [isPendingVote, setIsPendingVote] = useState(-1); + const [isPendingExecute, setIsPendingExecute] = useState(false); + const [isPendingRelease, setIsPendingRelease] = useState(false); const [selectedDiscussionUrl, setSelectedDiscussionUrl] = useState(undefined); const isSemiSmallScreen = useMediaQuery("(max-width: 745px)"); @@ -150,8 +152,12 @@ const ProposalDetails = ({ chainId, address, connect, config }) => { return url; }, [proposalProposer, config]); + const isPending = useMemo(() => { + return isPendingExecute || isPendingRelease || isPendingVote > -1; + }, [isPendingExecute, isPendingRelease, isPendingVote]); + const handleVote = useCallback(async (support) => { - setIsPending(true); + setIsPendingVote(support); const result = await castVote(chainId, address, proposalId, support); if (result) { @@ -161,21 +167,21 @@ const ProposalDetails = ({ chainId, address, connect, config }) => { setStorageValue(chainId, address, VOTED_PROPOSALS_PREFIX, proposals.map(id => id.toString())); await queryClient.invalidateQueries(); } - setIsPending(false); + setIsPendingVote(-1); }, [chainId, address, proposalId]); const handleExecute = async () => { - setIsPending(true); + setIsPendingExecute(true); await executeProposal(chainId, address, proposalId); await queryClient.invalidateQueries(); - setIsPending(false); + setIsPendingExecute(false); } const handleRelease = async () => { - setIsPending(true); + setIsPendingRelease(true); await releaseLocked(chainId, address, proposalId); await queryClient.invalidateQueries(); - setIsPending(false); + setIsPendingRelease(false); } return ( @@ -292,16 +298,18 @@ const ProposalDetails = ({ chainId, address, connect, config }) => { handleVote(1)} > - {isPending ? "Voting..." : "For"} + {isPendingVote === 1 ? "Voting For..." : "For"} handleVote(0)} > - {isPending ? "Voting..." : "Against"} + {isPendingVote === 0 ? "Voting Against..." : "Against"} : { chainId={chainId} proposalId={id} isPending={isPending} + isPendingExecute={isPendingExecute} + isPendingRelease={isPendingRelease} /> @@ -392,7 +402,20 @@ const ProposalDetails = ({ chainId, address, connect, config }) => { ) } -const VotingTimeline = ({ connect, handleExecute, handleRelease, proposalLocked, proposalId, chainId, state, address, isProposer, isPending }) => { +const VotingTimeline = ({ + connect, + handleExecute, + handleRelease, + proposalLocked, + proposalId, + chainId, + state, + address, + isProposer, + isPending, + isPendingExecute, + isPendingRelease, +}) => { const { delay: propsalVotingDelay } = useProposalVotingDelay(chainId, proposalId); const { snapshot: proposalSnapshot } = useProposalSnapshot(chainId, proposalId); const { deadline: proposalDeadline } = useProposalDeadline(chainId, proposalId); @@ -414,13 +437,15 @@ const VotingTimeline = ({ connect, handleExecute, handleRelease, proposalLocked, {(isProposer && (proposalLocked?._value ?? 0n) > 0n) && address === "" ? connect() : handleRelease()} > - {address === "" ? "Connect" : "Release"} + {address === "" ? "Connect" : isPendingRelease ? "Releasing..." : "Release"} } address === "" ? connect() : handleExecute()} > @@ -428,7 +453,7 @@ const VotingTimeline = ({ connect, handleExecute, handleRelease, proposalLocked, ? "Connect" : state !== 4 ? convertStatusToLabel(state) - : isPending ? "Executing..." : "Execute" + : isPendingExecute ? "Executing..." : "Execute" }