[xc-admin] add approve/reject/execute/cancel buttons (#576)
* add approve/reject/execute/cancel buttons * fix useMultisig hook not returning correct isLoading value
This commit is contained in:
parent
62083eb6d6
commit
0e00fb0d4a
|
@ -13,6 +13,7 @@ import {
|
||||||
useEffect,
|
useEffect,
|
||||||
useState,
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
import {
|
import {
|
||||||
ExecutePostedVaa,
|
ExecutePostedVaa,
|
||||||
getMultisigCluster,
|
getMultisigCluster,
|
||||||
|
@ -26,6 +27,7 @@ import {
|
||||||
import { ClusterContext } from '../../contexts/ClusterContext'
|
import { ClusterContext } from '../../contexts/ClusterContext'
|
||||||
import { useMultisigContext } from '../../contexts/MultisigContext'
|
import { useMultisigContext } from '../../contexts/MultisigContext'
|
||||||
import CopyIcon from '../../images/icons/copy.inline.svg'
|
import CopyIcon from '../../images/icons/copy.inline.svg'
|
||||||
|
import { capitalizeFirstLetter } from '../../utils/capitalizeFirstLetter'
|
||||||
import ClusterSwitch from '../ClusterSwitch'
|
import ClusterSwitch from '../ClusterSwitch'
|
||||||
import Loadbar from '../loaders/Loadbar'
|
import Loadbar from '../loaders/Loadbar'
|
||||||
|
|
||||||
|
@ -115,6 +117,8 @@ const Proposal = ({
|
||||||
const { cluster } = useContext(ClusterContext)
|
const { cluster } = useContext(ClusterContext)
|
||||||
const { squads, isLoading: isMultisigLoading } = useMultisigContext()
|
const { squads, isLoading: isMultisigLoading } = useMultisigContext()
|
||||||
|
|
||||||
|
const proposalStatus = proposal ? Object.keys(proposal.status)[0] : 'unknown'
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchProposalInstructions = async () => {
|
const fetchProposalInstructions = async () => {
|
||||||
const multisigParser = MultisigParser.fromCluster(
|
const multisigParser = MultisigParser.fromCluster(
|
||||||
|
@ -145,6 +149,50 @@ const Proposal = ({
|
||||||
fetchProposalInstructions()
|
fetchProposalInstructions()
|
||||||
}, [proposal, squads, cluster])
|
}, [proposal, squads, cluster])
|
||||||
|
|
||||||
|
const handleClickApprove = async () => {
|
||||||
|
if (proposal && squads) {
|
||||||
|
try {
|
||||||
|
await squads.approveTransaction(proposal.publicKey)
|
||||||
|
toast.success(`Approved proposal ${proposal.publicKey.toBase58()}`)
|
||||||
|
} catch (e: any) {
|
||||||
|
toast.error(capitalizeFirstLetter(e.message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClickReject = async () => {
|
||||||
|
if (proposal && squads) {
|
||||||
|
try {
|
||||||
|
await squads.rejectTransaction(proposal.publicKey)
|
||||||
|
toast.success(`Rejected proposal ${proposal.publicKey.toBase58()}`)
|
||||||
|
} catch (e: any) {
|
||||||
|
toast.error(capitalizeFirstLetter(e.message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClickExecute = async () => {
|
||||||
|
if (proposal && squads) {
|
||||||
|
try {
|
||||||
|
await squads.executeTransaction(proposal.publicKey)
|
||||||
|
toast.success(`Executed proposal ${proposal.publicKey.toBase58()}`)
|
||||||
|
} catch (e: any) {
|
||||||
|
toast.error(capitalizeFirstLetter(e.message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClickCancel = async () => {
|
||||||
|
if (proposal && squads) {
|
||||||
|
try {
|
||||||
|
await squads.cancelTransaction(proposal.publicKey)
|
||||||
|
toast.success(`Cancelled proposal ${proposal.publicKey.toBase58()}`)
|
||||||
|
} catch (e: any) {
|
||||||
|
toast.error(capitalizeFirstLetter(e.message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return proposal !== undefined &&
|
return proposal !== undefined &&
|
||||||
multisig !== undefined &&
|
multisig !== undefined &&
|
||||||
!isMultisigLoading &&
|
!isMultisigLoading &&
|
||||||
|
@ -153,6 +201,10 @@ const Proposal = ({
|
||||||
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4 lg:col-span-2">
|
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4 lg:col-span-2">
|
||||||
<h4 className="h4 font-semibold">Info</h4>
|
<h4 className="h4 font-semibold">Info</h4>
|
||||||
<hr className="border-gray-700" />
|
<hr className="border-gray-700" />
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<div>Status</div>
|
||||||
|
<div>{Object.keys(proposal.status)[0]}</div>
|
||||||
|
</div>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<div>Proposal</div>
|
<div>Proposal</div>
|
||||||
<div>{proposal.publicKey.toBase58()}</div>
|
<div>{proposal.publicKey.toBase58()}</div>
|
||||||
|
@ -169,7 +221,7 @@ const Proposal = ({
|
||||||
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4 lg:col-span-1">
|
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4 lg:col-span-1">
|
||||||
<h4 className="h4 mb-4 font-semibold">Results</h4>
|
<h4 className="h4 mb-4 font-semibold">Results</h4>
|
||||||
<hr className="border-gray-700" />
|
<hr className="border-gray-700" />
|
||||||
<div className="grid grid-cols-3 justify-center gap-4 pt-5 text-center align-middle">
|
<div className="grid grid-cols-3 justify-center gap-4 text-center align-middle">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-bold">Confirmed</div>
|
<div className="font-bold">Confirmed</div>
|
||||||
<div className="text-lg">{proposal.approved.length}</div>
|
<div className="text-lg">{proposal.approved.length}</div>
|
||||||
|
@ -185,6 +237,37 @@ const Proposal = ({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{proposalStatus === 'active' ? (
|
||||||
|
<div className="flex items-center justify-between px-8 pt-3">
|
||||||
|
<button
|
||||||
|
className="action-btn text-base"
|
||||||
|
onClick={handleClickApprove}
|
||||||
|
>
|
||||||
|
Approve
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="sub-action-btn text-base"
|
||||||
|
onClick={handleClickReject}
|
||||||
|
>
|
||||||
|
Reject
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : proposalStatus === 'executeReady' ? (
|
||||||
|
<div className="flex items-center justify-between px-8 pt-3">
|
||||||
|
<button
|
||||||
|
className="action-btn text-base"
|
||||||
|
onClick={handleClickExecute}
|
||||||
|
>
|
||||||
|
Execute
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="sub-action-btn text-base"
|
||||||
|
onClick={handleClickCancel}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4">
|
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4">
|
||||||
<h4 className="h4 font-semibold">Instructions</h4>
|
<h4 className="h4 font-semibold">Instructions</h4>
|
||||||
|
|
|
@ -95,6 +95,7 @@ export const useMultisig = (wallet: Wallet): MultisigHookData => {
|
||||||
publicKey: new PublicKey(0),
|
publicKey: new PublicKey(0),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
if (cancelled) return
|
||||||
setUpgradeMultisigAccount(
|
setUpgradeMultisigAccount(
|
||||||
await squads.getMultisig(
|
await squads.getMultisig(
|
||||||
UPGRADE_MULTISIG[getMultisigCluster(cluster)]
|
UPGRADE_MULTISIG[getMultisigCluster(cluster)]
|
||||||
|
@ -109,6 +110,7 @@ export const useMultisig = (wallet: Wallet): MultisigHookData => {
|
||||||
} else {
|
} else {
|
||||||
setSecurityMultisigAccount(undefined)
|
setSecurityMultisigAccount(undefined)
|
||||||
}
|
}
|
||||||
|
if (cancelled) return
|
||||||
setUpgradeMultisigProposals(
|
setUpgradeMultisigProposals(
|
||||||
await getSortedProposals(
|
await getSortedProposals(
|
||||||
squads,
|
squads,
|
||||||
|
@ -144,7 +146,9 @@ export const useMultisig = (wallet: Wallet): MultisigHookData => {
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
|
||||||
return () => {}
|
return () => {
|
||||||
|
cancelled = true
|
||||||
|
}
|
||||||
}, [urlsIndex, cluster, wallet])
|
}, [urlsIndex, cluster, wallet])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -284,3 +284,7 @@
|
||||||
.action-btn {
|
.action-btn {
|
||||||
@apply h-[45px] rounded-full bg-pythPurple px-8 font-mono font-semibold uppercase leading-none transition-colors hover:bg-mediumSlateBlue disabled:opacity-70 disabled:hover:bg-pythPurple;
|
@apply h-[45px] rounded-full bg-pythPurple px-8 font-mono font-semibold uppercase leading-none transition-colors hover:bg-mediumSlateBlue disabled:opacity-70 disabled:hover:bg-pythPurple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sub-action-btn {
|
||||||
|
@apply h-[45px] rounded-full bg-darkGray2 px-8 font-mono font-semibold uppercase leading-none transition-colors hover:bg-darkGray4 disabled:opacity-70 disabled:hover:bg-darkGray2;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue