@@ -13,6 +13,7 @@ import {
1313 useEffect ,
1414 useState ,
1515} from 'react'
16+ import toast from 'react-hot-toast'
1617import {
1718 ExecutePostedVaa ,
1819 getMultisigCluster ,
@@ -26,6 +27,7 @@ import {
2627import { ClusterContext } from '../../contexts/ClusterContext'
2728import { useMultisigContext } from '../../contexts/MultisigContext'
2829import CopyIcon from '../../images/icons/copy.inline.svg'
30+ import { capitalizeFirstLetter } from '../../utils/capitalizeFirstLetter'
2931import ClusterSwitch from '../ClusterSwitch'
3032import Loadbar from '../loaders/Loadbar'
3133
@@ -115,6 +117,8 @@ const Proposal = ({
115117 const { cluster } = useContext ( ClusterContext )
116118 const { squads, isLoading : isMultisigLoading } = useMultisigContext ( )
117119
120+ const proposalStatus = proposal ? Object . keys ( proposal . status ) [ 0 ] : 'unknown'
121+
118122 useEffect ( ( ) => {
119123 const fetchProposalInstructions = async ( ) => {
120124 const multisigParser = MultisigParser . fromCluster (
@@ -145,6 +149,50 @@ const Proposal = ({
145149 fetchProposalInstructions ( )
146150 } , [ proposal , squads , cluster ] )
147151
152+ const handleClickApprove = async ( ) => {
153+ if ( proposal && squads ) {
154+ try {
155+ await squads . approveTransaction ( proposal . publicKey )
156+ toast . success ( `Approved proposal ${ proposal . publicKey . toBase58 ( ) } ` )
157+ } catch ( e : any ) {
158+ toast . error ( capitalizeFirstLetter ( e . message ) )
159+ }
160+ }
161+ }
162+
163+ const handleClickReject = async ( ) => {
164+ if ( proposal && squads ) {
165+ try {
166+ await squads . rejectTransaction ( proposal . publicKey )
167+ toast . success ( `Rejected proposal ${ proposal . publicKey . toBase58 ( ) } ` )
168+ } catch ( e : any ) {
169+ toast . error ( capitalizeFirstLetter ( e . message ) )
170+ }
171+ }
172+ }
173+
174+ const handleClickExecute = async ( ) => {
175+ if ( proposal && squads ) {
176+ try {
177+ await squads . executeTransaction ( proposal . publicKey )
178+ toast . success ( `Executed proposal ${ proposal . publicKey . toBase58 ( ) } ` )
179+ } catch ( e : any ) {
180+ toast . error ( capitalizeFirstLetter ( e . message ) )
181+ }
182+ }
183+ }
184+
185+ const handleClickCancel = async ( ) => {
186+ if ( proposal && squads ) {
187+ try {
188+ await squads . cancelTransaction ( proposal . publicKey )
189+ toast . success ( `Cancelled proposal ${ proposal . publicKey . toBase58 ( ) } ` )
190+ } catch ( e : any ) {
191+ toast . error ( capitalizeFirstLetter ( e . message ) )
192+ }
193+ }
194+ }
195+
148196 return proposal !== undefined &&
149197 multisig !== undefined &&
150198 ! isMultisigLoading &&
@@ -153,6 +201,10 @@ const Proposal = ({
153201 < div className = "col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4 lg:col-span-2" >
154202 < h4 className = "h4 font-semibold" > Info</ h4 >
155203 < hr className = "border-gray-700" />
204+ < div className = "flex justify-between" >
205+ < div > Status</ div >
206+ < div > { Object . keys ( proposal . status ) [ 0 ] } </ div >
207+ </ div >
156208 < div className = "flex justify-between" >
157209 < div > Proposal</ div >
158210 < div > { proposal . publicKey . toBase58 ( ) } </ div >
@@ -169,7 +221,7 @@ const Proposal = ({
169221 < div className = "col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4 lg:col-span-1" >
170222 < h4 className = "h4 mb-4 font-semibold" > Results</ h4 >
171223 < hr className = "border-gray-700" />
172- < div className = "grid grid-cols-3 justify-center gap-4 pt-5 text-center align-middle" >
224+ < div className = "grid grid-cols-3 justify-center gap-4 text-center align-middle" >
173225 < div >
174226 < div className = "font-bold" > Confirmed</ div >
175227 < div className = "text-lg" > { proposal . approved . length } </ div >
@@ -185,6 +237,37 @@ const Proposal = ({
185237 </ div >
186238 </ div >
187239 </ div >
240+ { proposalStatus === 'active' ? (
241+ < div className = "flex items-center justify-between px-8 pt-3" >
242+ < button
243+ className = "action-btn text-base"
244+ onClick = { handleClickApprove }
245+ >
246+ Approve
247+ </ button >
248+ < button
249+ className = "sub-action-btn text-base"
250+ onClick = { handleClickReject }
251+ >
252+ Reject
253+ </ button >
254+ </ div >
255+ ) : proposalStatus === 'executeReady' ? (
256+ < div className = "flex items-center justify-between px-8 pt-3" >
257+ < button
258+ className = "action-btn text-base"
259+ onClick = { handleClickExecute }
260+ >
261+ Execute
262+ </ button >
263+ < button
264+ className = "sub-action-btn text-base"
265+ onClick = { handleClickCancel }
266+ >
267+ Cancel
268+ </ button >
269+ </ div >
270+ ) : null }
188271 </ div >
189272 < div className = "col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4" >
190273 < h4 className = "h4 font-semibold" > Instructions</ h4 >
0 commit comments