From 7c36326bffd370875d7a5e90f58020c79cf30bd8 Mon Sep 17 00:00:00 2001 From: Gancho Radkov <43912948+ganchoradkov@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:03:35 +0200 Subject: [PATCH] feat: loading indicators (#402) * feat: adds loading indicators on all modals * feat: implements modal loader for session propose * feat: implements loaders for each separate button * feat: adds loaders on disconnect & when proposing session on known pairing topic * refactor: restructure modal properties to avoid conditional hooks --------- Co-authored-by: Gancho Radkov --- .../src/contexts/ClientContext.tsx | 16 +- .../react-dapp-v2/src/modals/LoaderModal.tsx | 29 +++ .../react-dapp-v2/src/modals/PairingModal.tsx | 27 ++- .../dapps/react-dapp-v2/src/pages/index.tsx | 21 +- .../react-wallet-v2/src/components/Modal.tsx | 52 +++-- .../src/components/ModalFooter.tsx | 23 ++- .../src/components/SessionChainCard.tsx | 4 +- .../react-wallet-v2/src/pages/session.tsx | 191 ++++++++---------- .../src/pages/walletconnect.tsx | 20 +- .../src/views/AuthRequestModal.tsx | 26 ++- .../src/views/RequestModal.tsx | 14 +- .../src/views/SessionProposalModal.tsx | 72 ++++--- .../src/views/SessionSendTransactionModal.tsx | 55 ++--- .../src/views/SessionSignCosmosModal.tsx | 25 ++- .../src/views/SessionSignKadenaModal.tsx | 26 ++- .../src/views/SessionSignModal.tsx | 26 ++- .../src/views/SessionSignMultiversxModal.tsx | 25 ++- .../src/views/SessionSignNearModal.tsx | 25 ++- .../src/views/SessionSignPolkadotModal.tsx | 25 ++- .../src/views/SessionSignSolanaModal.tsx | 25 ++- .../src/views/SessionSignTezosModal.tsx | 25 ++- .../src/views/SessionSignTronModal.tsx | 25 ++- .../src/views/SessionSignTypedDataModal.tsx | 23 ++- .../react-wallet-v2/src/views/TheatPrompt.tsx | 6 - 24 files changed, 492 insertions(+), 314 deletions(-) create mode 100644 advanced/dapps/react-dapp-v2/src/modals/LoaderModal.tsx diff --git a/advanced/dapps/react-dapp-v2/src/contexts/ClientContext.tsx b/advanced/dapps/react-dapp-v2/src/contexts/ClientContext.tsx index f384c27..216dc61 100644 --- a/advanced/dapps/react-dapp-v2/src/contexts/ClientContext.tsx +++ b/advanced/dapps/react-dapp-v2/src/contexts/ClientContext.tsx @@ -200,17 +200,11 @@ export function ClientContextProvider({ throw new Error("Session is not connected"); } - try { - await client.disconnect({ - topic: session.topic, - reason: getSdkError("USER_DISCONNECTED"), - }); - } catch (error) { - toast.error((error as Error).message, { - position: "bottom-left", - }); - return; - } + await client.disconnect({ + topic: session.topic, + reason: getSdkError("USER_DISCONNECTED"), + }); + // Reset app state after disconnect. reset(); }, [client, session]); diff --git a/advanced/dapps/react-dapp-v2/src/modals/LoaderModal.tsx b/advanced/dapps/react-dapp-v2/src/modals/LoaderModal.tsx new file mode 100644 index 0000000..cc40242 --- /dev/null +++ b/advanced/dapps/react-dapp-v2/src/modals/LoaderModal.tsx @@ -0,0 +1,29 @@ +import * as React from "react"; + +import Loader from "../components/Loader"; +import { SContainer } from "../components/shared"; + +import { SModalContainer, SModalParagraph, SModalTitle } from "./shared"; + +interface LoaderModal { + title: string; + text?: string; +} + +const LoaderModal = (props: LoaderModal) => { + const { title, text } = props; + return ( + <> + + {title} + + +
+ {text} +
+
+ + ); +}; + +export default LoaderModal; diff --git a/advanced/dapps/react-dapp-v2/src/modals/PairingModal.tsx b/advanced/dapps/react-dapp-v2/src/modals/PairingModal.tsx index c80cc15..e7d1aad 100644 --- a/advanced/dapps/react-dapp-v2/src/modals/PairingModal.tsx +++ b/advanced/dapps/react-dapp-v2/src/modals/PairingModal.tsx @@ -7,6 +7,8 @@ import Pairing from "../components/Pairing"; import { STable } from "../components/shared"; import { SModalContainer, SModalTitle } from "./shared"; +import LoaderModal from "./LoaderModal"; +import toast from "react-hot-toast"; interface PairingModalProps { pairings: PairingTypes.Struct[]; @@ -15,7 +17,28 @@ interface PairingModalProps { const PairingModal = (props: PairingModalProps) => { const { pairings, connect } = props; - return ( + const [pairing, setPairing] = React.useState(); + + const onConnect = React.useCallback( + async (pairing: PairingTypes.Struct) => { + try { + setPairing(pairing); + await connect({ topic: pairing.topic }); + } catch (error) { + toast.error((error as Error).message, { + position: "bottom-left", + }); + setPairing(undefined); + } + }, + [connect] + ); + return pairing ? ( + + ) : ( {"Select available pairing or create new one"} @@ -23,7 +46,7 @@ const PairingModal = (props: PairingModalProps) => { connect({ topic: pairing.topic })} + onClick={() => onConnect(pairing)} /> ))} diff --git a/advanced/dapps/react-dapp-v2/src/pages/index.tsx b/advanced/dapps/react-dapp-v2/src/pages/index.tsx index baf6f0c..c37457b 100644 --- a/advanced/dapps/react-dapp-v2/src/pages/index.tsx +++ b/advanced/dapps/react-dapp-v2/src/pages/index.tsx @@ -1,5 +1,6 @@ import type { NextPage } from "next"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; +import toast from "react-hot-toast"; import Banner from "../components/Banner"; import Blockchain from "../components/Blockchain"; @@ -42,6 +43,7 @@ import { useJsonRpc } from "../contexts/JsonRpcContext"; import { useChainData } from "../contexts/ChainDataContext"; import Icon from "../components/Icon"; import OriginSimulationDropdown from "../components/OriginSimulationDropdown"; +import LoaderModal from "../modals/LoaderModal"; // Normal import does not work here const { version } = require("@walletconnect/sign-client/package.json"); @@ -53,6 +55,7 @@ const Home: NextPage = () => { const openPairingModal = () => setModal("pairing"); const openPingModal = () => setModal("ping"); const openRequestModal = () => setModal("request"); + const openDisconnectModal = () => setModal("disconnect"); // Initialize the WalletConnect client. const { @@ -117,6 +120,18 @@ const Home: NextPage = () => { await ping(); }; + const onDisconnect = useCallback(async () => { + openDisconnectModal(); + try { + await disconnect(); + } catch (error) { + toast.error((error as Error).message, { + position: "bottom-left", + }); + } + closeModal(); + }, [disconnect]); + async function emit() { if (typeof client === "undefined") { throw new Error("WalletConnect is not initialized"); @@ -443,6 +458,8 @@ const Home: NextPage = () => { ); case "ping": return ; + case "disconnect": + return ; default: return null; } @@ -522,7 +539,7 @@ const Home: NextPage = () => {
diff --git a/advanced/wallets/react-wallet-v2/src/components/Modal.tsx b/advanced/wallets/react-wallet-v2/src/components/Modal.tsx index aee6539..d706312 100644 --- a/advanced/wallets/react-wallet-v2/src/components/Modal.tsx +++ b/advanced/wallets/react-wallet-v2/src/components/Modal.tsx @@ -14,7 +14,7 @@ import SessionSignTypedDataModal from '@/views/SessionSignTypedDataModal' import SessionUnsuportedMethodModal from '@/views/SessionUnsuportedMethodModal' import { Modal as NextModal } from '@nextui-org/react' import { useSnapshot } from 'valtio' -import { useCallback } from 'react' +import { useCallback, useMemo } from 'react' import AuthRequestModal from '@/views/AuthRequestModal' export default function Modal() { @@ -26,6 +26,41 @@ export default function Modal() { } }, [open]) + const componentView = useMemo(() => { + switch (view) { + case 'SessionProposalModal': + return + case 'SessionSignModal': + return + case 'SessionSignTypedDataModal': + return + case 'SessionSendTransactionModal': + return + case 'SessionUnsuportedMethodModal': + return + case 'SessionSignCosmosModal': + return + case 'SessionSignSolanaModal': + return + case 'SessionSignPolkadotModal': + return + case 'SessionSignNearModal': + return + case 'SessionSignMultiversxModal': + return + case 'SessionSignTronModal': + return + case 'SessionSignTezosModal': + return + case 'SessionSignKadenaModal': + return + case 'AuthRequestModal': + return + default: + return null + } + }, [view]) + return ( - {view === 'SessionProposalModal' && } - {view === 'SessionSignModal' && } - {view === 'SessionSignTypedDataModal' && } - {view === 'SessionSendTransactionModal' && } - {view === 'SessionUnsuportedMethodModal' && } - {view === 'SessionSignCosmosModal' && } - {view === 'SessionSignSolanaModal' && } - {view === 'SessionSignPolkadotModal' && } - {view === 'SessionSignNearModal' && } - {view === 'SessionSignMultiversxModal' && } - {view === 'SessionSignTronModal' && } - {view === 'SessionSignTezosModal' && } - {view === 'SessionSignKadenaModal' && } - {view === 'AuthRequestModal' && } + {componentView} ) } diff --git a/advanced/wallets/react-wallet-v2/src/components/ModalFooter.tsx b/advanced/wallets/react-wallet-v2/src/components/ModalFooter.tsx index 18e6b0a..5983bfd 100644 --- a/advanced/wallets/react-wallet-v2/src/components/ModalFooter.tsx +++ b/advanced/wallets/react-wallet-v2/src/components/ModalFooter.tsx @@ -1,19 +1,26 @@ import SettingsStore from '@/store/SettingsStore' -import { Button, Modal, Row } from '@nextui-org/react' +import { Button, Modal, Row, Loading } from '@nextui-org/react' import { useMemo } from 'react' import { useSnapshot } from 'valtio' - +export interface LoaderProps { + color?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'white' + active?: boolean +} interface Props { onApprove: () => void onReject: () => void infoBoxCondition?: boolean infoBoxText?: string disabledApprove?: boolean + approveLoader?: LoaderProps + rejectLoader?: LoaderProps } export default function ModalFooter({ onApprove, + approveLoader, onReject, + rejectLoader, infoBoxCondition, infoBoxText, disabledApprove @@ -47,7 +54,11 @@ export default function ModalFooter({ onPress={onReject} data-testid="session-reject-button" > - Reject + {rejectLoader && rejectLoader.active ? ( + + ) : ( + 'Reject' + )} diff --git a/advanced/wallets/react-wallet-v2/src/components/SessionChainCard.tsx b/advanced/wallets/react-wallet-v2/src/components/SessionChainCard.tsx index 39363d6..64b72c0 100644 --- a/advanced/wallets/react-wallet-v2/src/components/SessionChainCard.tsx +++ b/advanced/wallets/react-wallet-v2/src/components/SessionChainCard.tsx @@ -44,7 +44,9 @@ export default function SessionChainCard({ namespace }: IProps) { namespace.accounts.forEach(account => { const [type, chain] = account.split(':') const chainId = `${type}:${chain}` - chains.push(chainId) + if (!chains.includes(chainId)) { + chains.push(chainId) + } }) return ( diff --git a/advanced/wallets/react-wallet-v2/src/pages/session.tsx b/advanced/wallets/react-wallet-v2/src/pages/session.tsx index e47021f..0b9e449 100644 --- a/advanced/wallets/react-wallet-v2/src/pages/session.tsx +++ b/advanced/wallets/react-wallet-v2/src/pages/session.tsx @@ -1,13 +1,13 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import PageHeader from '@/components/PageHeader' import ProjectInfoCard from '@/components/ProjectInfoCard' import SessionChainCard from '@/components/SessionChainCard' -import SettingsStore from '@/store/SettingsStore' +import { styledToast } from '@/utils/HelperUtil' import { web3wallet } from '@/utils/WalletConnectUtil' import { Button, Divider, Loading, Row, Text } from '@nextui-org/react' import { getSdkError } from '@walletconnect/utils' import { useRouter } from 'next/router' -import { Fragment, useEffect, useState } from 'react' -import { useSnapshot } from 'valtio' +import { Fragment, useCallback, useEffect, useMemo, useState } from 'react' /** * Component @@ -16,9 +16,10 @@ export default function SessionPage() { const [topic, setTopic] = useState('') const [updated, setUpdated] = useState(new Date()) const { query, replace } = useRouter() - const [loading, setLoading] = useState(false) - - const { activeChainId } = useSnapshot(SettingsStore.state) + const [updateLoading, setUpdateLoading] = useState(false) + const [pingLoading, setPingLoading] = useState(false) + const [emitLoading, setEmitLoading] = useState(false) + const [deleteLoading, setDeleteLoading] = useState(false) useEffect(() => { if (query?.topic) { @@ -26,96 +27,81 @@ export default function SessionPage() { } }, [query]) - const session = web3wallet.engine.signClient.session.values.find(s => s.topic === topic) - - if (!session) { - return null - } + const session = useMemo( + () => web3wallet.engine.signClient.session.values.find(s => s.topic === topic), + [topic] + ) + const namespaces = useMemo(() => session?.namespaces, [session]) // Get necessary data from session - const expiryDate = new Date(session.expiry * 1000) - const { namespaces } = session + const expiryDate = useMemo(() => new Date(session?.expiry! * 1000), [session]) // Handle deletion of a session - async function onDeleteSession() { - setLoading(true) - await web3wallet.disconnectSession({ topic, reason: getSdkError('USER_DISCONNECTED') }) - replace('/sessions') - setLoading(false) - } + const onDeleteSession = useCallback(async () => { + setDeleteLoading(true) + try { + await web3wallet.disconnectSession({ topic, reason: getSdkError('USER_DISCONNECTED') }) + replace('/sessions') + } catch (e) { + styledToast((e as Error).message, 'error') + } + setDeleteLoading(false) + }, [topic, replace]) - async function onSessionPing() { - setLoading(true) + const onSessionPing = useCallback(async () => { + setPingLoading(true) await web3wallet.engine.signClient.ping({ topic }) - setLoading(false) - } + setPingLoading(false) + }, [topic]) - async function onSessionEmit() { - setLoading(true) - await web3wallet.emitSessionEvent({ - topic, - event: { name: 'chainChanged', data: 'Hello World' }, - chainId: activeChainId.toString() // chainId: 'eip155:1' - }) - setLoading(false) - } + const onSessionEmit = useCallback(async () => { + setEmitLoading(true) + try { + const namespace = Object.keys(session?.namespaces!)[0] + const chainId = session?.namespaces[namespace].chains?.[0] + await web3wallet.emitSessionEvent({ + topic, + event: { name: 'chainChanged', data: 'Hello World' }, + chainId: chainId! // chainId: 'eip155:1' + }) + } catch (e) { + styledToast((e as Error).message, 'error') + } + setEmitLoading(false) + }, [session?.namespaces, topic]) - async function onSessionUpdate() { - setLoading(true) - const session = web3wallet.engine.signClient.session.get(topic) - const baseAddress = '0x70012948c348CBF00806A3C79E3c5DAdFaAa347' - const namespaceKeyToUpdate = Object.keys(session?.namespaces)[0] - const namespaceToUpdate = session?.namespaces[namespaceKeyToUpdate] - await web3wallet.updateSession({ - topic, - namespaces: { - ...session?.namespaces, - [namespaceKeyToUpdate]: { - ...session?.namespaces[namespaceKeyToUpdate], - accounts: namespaceToUpdate.accounts.concat( - `${namespaceToUpdate.chains?.[0]}:${baseAddress}${Math.floor( - Math.random() * (9 - 1 + 1) + 0 - )}` - ) // generates random number between 0 and 9 + const onSessionUpdate = useCallback(async () => { + setUpdateLoading(true) + try { + const session = web3wallet.engine.signClient.session.get(topic) + const baseAddress = '0x70012948c348CBF00806A3C79E3c5DAdFaAa347' + const namespaceKeyToUpdate = Object.keys(session?.namespaces)[0] + const namespaceToUpdate = session?.namespaces[namespaceKeyToUpdate] + await web3wallet.updateSession({ + topic, + namespaces: { + ...session?.namespaces, + [namespaceKeyToUpdate]: { + ...session?.namespaces[namespaceKeyToUpdate], + accounts: namespaceToUpdate.accounts.concat( + `${namespaceToUpdate.chains?.[0]}:${baseAddress}${Math.floor( + Math.random() * (9 - 1 + 1) + 0 + )}` + ) // generates random number between 0 and 9 + } } - } - }) - setUpdated(new Date()) - setLoading(false) - } + }) + setUpdated(new Date()) + } catch (e) { + styledToast((e as Error).message, 'error') + } + setUpdateLoading(false) + }, [topic]) - // function renderAccountSelection(chain: string) { - // if (isEIP155Chain(chain)) { - // return ( - // - // ) - // } else if (isCosmosChain(chain)) { - // return ( - // - // ) - // } else if (isSolanaChain(chain)) { - // return ( - // - // ) - // } - // } - - return ( + console.log('session', session) + return !session ? ( + <> + ) : ( @@ -123,18 +109,19 @@ export default function SessionPage() { - {Object.keys(namespaces).map(chain => { - return ( - - {`Review ${chain} permissions`} - - - - ) - })} + {namespaces && + Object.keys(namespaces).map(chain => { + return ( + + {`Review ${chain} permissions`} + + + + ) + })} Expiry @@ -158,7 +145,7 @@ export default function SessionPage() { onClick={onDeleteSession} data-testid="session-delete-button" > - {loading ? : 'Delete'} + {deleteLoading ? : 'Delete'} @@ -170,7 +157,7 @@ export default function SessionPage() { onClick={onSessionPing} data-testid="session-ping-button" > - {loading ? : 'Ping'} + {pingLoading ? : 'Ping'} @@ -182,7 +169,7 @@ export default function SessionPage() { onClick={onSessionEmit} data-testid="session-emit-button" > - {loading ? : 'Emit'} + {emitLoading ? : 'Emit'} @@ -194,7 +181,7 @@ export default function SessionPage() { onClick={onSessionUpdate} data-testid="session-update-button" > - {loading ? : 'Update'} + {updateLoading ? : 'Update'} diff --git a/advanced/wallets/react-wallet-v2/src/pages/walletconnect.tsx b/advanced/wallets/react-wallet-v2/src/pages/walletconnect.tsx index 586041c..ece8d8e 100644 --- a/advanced/wallets/react-wallet-v2/src/pages/walletconnect.tsx +++ b/advanced/wallets/react-wallet-v2/src/pages/walletconnect.tsx @@ -5,20 +5,36 @@ import { web3wallet } from '@/utils/WalletConnectUtil' import { Button, Input, Loading, Text } from '@nextui-org/react' import { Fragment, useState } from 'react' import { styledToast } from '@/utils/HelperUtil' +import ModalStore from '@/store/ModalStore' export default function WalletConnectPage() { const [uri, setUri] = useState('') const [loading, setLoading] = useState(false) async function onConnect(uri: string) { + const { topic: pairingTopic } = parseUri(uri) + // if for some reason, the proposal is not received, we need to close the modal when the pairing expires (5mins) + const pairingExpiredListener = ({ topic }: { topic: string }) => { + if (pairingTopic === topic) { + styledToast('Pairing expired. Please try again with new Connection URI', 'error') + ModalStore.close() + web3wallet.core.pairing.events.removeListener('pairing_expire', pairingExpiredListener) + } + } + web3wallet.once('session_proposal', () => { + web3wallet.core.pairing.events.removeListener('pairing_expire', pairingExpiredListener) + }) try { setLoading(true) + ModalStore.open('SessionProposalModal', {}) + web3wallet.core.pairing.events.on('pairing_expire', pairingExpiredListener) await web3wallet.pair({ uri }) } catch (error) { styledToast((error as Error).message, 'error') + ModalStore.close() } finally { - setUri('') setLoading(false) + setUri('') } } @@ -49,7 +65,7 @@ export default function WalletConnectPage() { color="gradient" data-testid="uri-connect-button" > - {loading ? : 'Connect'} + {loading ? : 'Connect'} } /> diff --git a/advanced/wallets/react-wallet-v2/src/views/AuthRequestModal.tsx b/advanced/wallets/react-wallet-v2/src/views/AuthRequestModal.tsx index 5bb451d..ac13a12 100644 --- a/advanced/wallets/react-wallet-v2/src/views/AuthRequestModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/AuthRequestModal.tsx @@ -1,12 +1,9 @@ -import { Fragment } from 'react' +/* eslint-disable react-hooks/rules-of-hooks */ +import { useCallback, useState } from 'react' import { useSnapshot } from 'valtio' -import { Col, Divider, Row, Text, Code } from '@nextui-org/react' +import { Col, Row, Text, Code } from '@nextui-org/react' import { getSdkError } from '@walletconnect/utils' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import SettingsStore from '@/store/SettingsStore' import { eip155Addresses, eip155Wallets } from '@/utils/EIP155WalletUtil' @@ -15,6 +12,8 @@ import RequestModal from './RequestModal' export default function AuthRequestModal() { const { account } = useSnapshot(SettingsStore.state) + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) console.log('modal data', ModalStore.state.data, account) // Get request and wallet data from store const request = ModalStore.state.data?.request @@ -32,8 +31,9 @@ export default function AuthRequestModal() { const message = web3wallet.formatMessage(params.cacaoPayload, iss) // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (request) { + setIsLoadingApprove(true) const signature = await eip155Wallets[address].signMessage(message) await web3wallet.respondAuthRequest( { @@ -45,13 +45,15 @@ export default function AuthRequestModal() { }, iss ) + setIsLoadingApprove(false) ModalStore.close() } - } + }, [request, address, message, iss]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (request) { + setIsLoadingReject(true) await web3wallet.respondAuthRequest( { id: request.id, @@ -59,15 +61,19 @@ export default function AuthRequestModal() { }, iss ) + setIsLoadingReject(false) ModalStore.close() } - } + }, [request, iss]) + return ( diff --git a/advanced/wallets/react-wallet-v2/src/views/RequestModal.tsx b/advanced/wallets/react-wallet-v2/src/views/RequestModal.tsx index 9d8df9e..cd879ed 100644 --- a/advanced/wallets/react-wallet-v2/src/views/RequestModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/RequestModal.tsx @@ -1,8 +1,8 @@ import { Fragment, ReactNode, useMemo, useState } from 'react' -import { Divider, Text } from '@nextui-org/react' +import { Divider } from '@nextui-org/react' import { CoreTypes } from '@walletconnect/types' -import ModalFooter from '@/components/ModalFooter' +import ModalFooter, { LoaderProps } from '@/components/ModalFooter' import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestModalContainer from '@/components/RequestModalContainer' import VerifyInfobox from '@/components/VerifyInfobox' @@ -19,12 +19,16 @@ interface IProps { infoBoxCondition?: boolean infoBoxText?: string disabledApprove?: boolean + approveLoader?: LoaderProps + rejectLoader?: LoaderProps } export default function RequestModal({ children, metadata, onApprove, onReject, + approveLoader, + rejectLoader, intention, infoBoxCondition, infoBoxText, @@ -57,6 +61,8 @@ export default function RequestModal({ ) }, [ + approveLoader, children, disabledApprove, infoBoxCondition, @@ -71,7 +78,8 @@ export default function RequestModal({ intention, metadata, onApprove, - onReject + onReject, + rejectLoader ]) return {isScam && !threatAcknowledged ? threatPromptContent : modalContent} } diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx index 180daec..ae73ad9 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx @@ -1,12 +1,12 @@ -import { Col, Divider, Grid, Row, Text, styled } from '@nextui-org/react' -import { Fragment, useCallback, useMemo } from 'react' +/* eslint-disable react-hooks/rules-of-hooks */ +import { Col, Grid, Loading, Row, Text, styled } from '@nextui-org/react' +import { useCallback, useMemo, useState } from 'react' import { buildApprovedNamespaces, getSdkError } from '@walletconnect/utils' +import { SignClientTypes } from '@walletconnect/types' import DoneIcon from '@mui/icons-material/Done' import CloseIcon from '@mui/icons-material/Close' -import ProjectInfoCard from '@/components/ProjectInfoCard' -import RequestModalContainer from '@/components/RequestModalContainer' import ModalStore from '@/store/ModalStore' import { cosmosAddresses } from '@/utils/CosmosWalletUtil' import { eip155Addresses } from '@/utils/EIP155WalletUtil' @@ -31,9 +31,8 @@ import { TRON_CHAINS, TRON_SIGNING_METHODS } from '@/data/TronData' import ChainDataMini from '@/components/ChainDataMini' import ChainAddressMini from '@/components/ChainAddressMini' import { getChainData } from '@/data/chainsUtil' -import VerifyInfobox from '@/components/VerifyInfobox' -import ModalFooter from '@/components/ModalFooter' import RequestModal from './RequestModal' +import { useSnapshot } from 'valtio' const StyledText = styled(Text, { fontWeight: 400 @@ -45,8 +44,12 @@ const StyledSpan = styled('span', { export default function SessionProposalModal() { // Get proposal data and wallet address from store - const proposal = ModalStore.state.data?.proposal - console.log('proposal', proposal) + const data = useSnapshot(ModalStore.state) + const proposal = data?.data?.proposal as SignClientTypes.EventArguments['session_proposal'] + + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) + console.log('proposal', data.data?.proposal) const supportedNamespaces = useMemo(() => { // eip155 const eip155Chains = Object.keys(EIP155_CHAINS) @@ -213,30 +216,10 @@ export default function SessionProposalModal() { } }, []) - const approveButtonColor: any = useMemo(() => { - switch (proposal?.verifyContext.verified.validation) { - case 'INVALID': - return 'error' - case 'UNKNOWN': - return 'warning' - default: - return 'success' - } - }, [proposal]) - - // Ensure proposal is defined - if (!proposal) { - return Missing proposal data - } - - // Get required proposal data - const { id, params } = proposal - - const { proposer, relays } = params - // Hanlde approve action, construct session namespace - async function onApprove() { + const onApprove = useCallback(async () => { if (proposal) { + setIsLoadingApprove(true) const namespaces = buildApprovedNamespaces({ proposal: proposal.params, supportedNamespaces @@ -246,39 +229,54 @@ export default function SessionProposalModal() { try { await web3wallet.approveSession({ - id, - relayProtocol: relays[0].protocol, + id: proposal.id, namespaces }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } } + setIsLoadingApprove(false) ModalStore.close() - } + }, [proposal, supportedNamespaces]) // Hanlde reject action - async function onReject() { + // eslint-disable-next-line react-hooks/rules-of-hooks + const onReject = useCallback(async () => { if (proposal) { try { + setIsLoadingReject(true) + await new Promise(resolve => setTimeout(resolve, 1000)) await web3wallet.rejectSession({ - id, + id: proposal.id, reason: getSdkError('USER_REJECTED_METHODS') }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } } + setIsLoadingReject(false) ModalStore.close() - } + }, [proposal]) - return ( + return !proposal ? ( + <> +
+ + Attempting to pair... +
+ + ) : ( 0} infoBoxText={`The following required chains are not supported by your wallet - ${notSupportedChains.toString()}`} disabledApprove={notSupportedChains.length > 0} diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSendTransactionModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSendTransactionModal.tsx index ac59d6d..09aa543 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSendTransactionModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSendTransactionModal.tsx @@ -1,13 +1,9 @@ -import { Fragment, useState } from 'react' -import { Divider, Modal, Text } from '@nextui-org/react' +import { useCallback, useState } from 'react' +import { Divider, Text } from '@nextui-org/react' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestDataCard from '@/components/RequestDataCard' import RequesDetailsCard from '@/components/RequestDetalilsCard' import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import { approveEIP155Request, rejectEIP155Request } from '@/utils/EIP155RequestHandlerUtil' import { styledToast } from '@/utils/HelperUtil' @@ -15,27 +11,23 @@ import { web3wallet } from '@/utils/WalletConnectUtil' import RequestModal from './RequestModal' export default function SessionSendTransactionModal() { - const [loading, setLoading] = useState(false) + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession - // Ensure request and wallet are defined - if (!requestEvent || !requestSession) { - return Missing request data - } - - // Get required proposal data - - const { topic, params } = requestEvent - const { request, chainId } = params - const transaction = request.params[0] + const topic = requestEvent?.topic + const params = requestEvent?.params + const chainId = params?.chainId + const request = params?.request + const transaction = request?.params[0] // Handle approve action - async function onApprove() { - if (requestEvent) { - setLoading(true) + const onApprove = useCallback(async () => { + if (requestEvent && topic) { + setIsLoadingApprove(true) try { const response = await approveEIP155Request(requestEvent) await web3wallet.respondSessionRequest({ @@ -43,16 +35,19 @@ export default function SessionSendTransactionModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { - if (requestEvent) { + const onReject = useCallback(async () => { + if (requestEvent && topic) { + setIsLoadingReject(true) const response = rejectEIP155Request(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -60,25 +55,31 @@ export default function SessionSendTransactionModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) - return ( + return request && requestSession ? ( - + + ) : ( + Request not found ) } diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSignCosmosModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSignCosmosModal.tsx index 0746cf6..4722ab0 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSignCosmosModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSignCosmosModal.tsx @@ -1,13 +1,10 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { Divider, Text } from '@nextui-org/react' -import { Fragment } from 'react' +import { useCallback, useState } from 'react' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestDataCard from '@/components/RequestDataCard' import RequesDetailsCard from '@/components/RequestDetalilsCard' import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import { approveCosmosRequest, rejectCosmosRequest } from '@/utils/CosmosRequestHandler' import { styledToast } from '@/utils/HelperUtil' @@ -18,6 +15,8 @@ export default function SessionSignCosmosModal() { // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Ensure request and wallet are defined if (!requestEvent || !requestSession) { @@ -29,8 +28,9 @@ export default function SessionSignCosmosModal() { const { chainId, request } = params // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (requestEvent) { + setIsLoadingApprove(true) const response = await approveCosmosRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -38,16 +38,19 @@ export default function SessionSignCosmosModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (requestEvent) { + setIsLoadingReject(true) const response = rejectCosmosRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -55,12 +58,14 @@ export default function SessionSignCosmosModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) return ( diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSignKadenaModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSignKadenaModal.tsx index 0c7d24e..d50a84a 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSignKadenaModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSignKadenaModal.tsx @@ -1,23 +1,21 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { Col, Divider, Row, Text } from '@nextui-org/react' -import { Fragment } from 'react' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestDataCard from '@/components/RequestDataCard' import RequestDetailsCard from '@/components/RequestDetalilsCard' -import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import { convertHexToUtf8, styledToast } from '@/utils/HelperUtil' import { approveKadenaRequest, rejectKadenaRequest } from '@/utils/KadenaRequestHandlerUtil' import { web3wallet } from '@/utils/WalletConnectUtil' import RequestModal from './RequestModal' +import { useCallback, useState } from 'react' export default function SessionSignKadenaModal() { // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Ensure request and wallet are defined if (!requestEvent || !requestSession) { @@ -32,8 +30,9 @@ export default function SessionSignKadenaModal() { const message = convertHexToUtf8(request.params.message) // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (requestEvent) { + setIsLoadingApprove(true) const response = await approveKadenaRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -41,16 +40,19 @@ export default function SessionSignKadenaModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (requestEvent) { + setIsLoadingReject(true) const response = rejectKadenaRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -58,12 +60,14 @@ export default function SessionSignKadenaModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) return ( diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSignModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSignModal.tsx index fc86bfc..6551848 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSignModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSignModal.tsx @@ -1,12 +1,8 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { Col, Divider, Row, Text } from '@nextui-org/react' -import { Fragment } from 'react' +import { useCallback, useState } from 'react' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequesDetailsCard from '@/components/RequestDetalilsCard' -import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import { approveEIP155Request, rejectEIP155Request } from '@/utils/EIP155RequestHandlerUtil' import { getSignParamsMessage, styledToast } from '@/utils/HelperUtil' @@ -16,6 +12,8 @@ export default function SessionSignModal() { // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Ensure request and wallet are defined if (!requestEvent || !requestSession) { @@ -30,8 +28,9 @@ export default function SessionSignModal() { const message = getSignParamsMessage(request.params) // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (requestEvent) { + setIsLoadingApprove(true) const response = await approveEIP155Request(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -39,16 +38,19 @@ export default function SessionSignModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (requestEvent) { + setIsLoadingReject(true) const response = rejectEIP155Request(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -56,12 +58,14 @@ export default function SessionSignModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) return ( diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSignMultiversxModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSignMultiversxModal.tsx index be4ca6f..54f8163 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSignMultiversxModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSignMultiversxModal.tsx @@ -1,13 +1,10 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { Divider, Text } from '@nextui-org/react' -import { Fragment } from 'react' +import { useCallback, useState } from 'react' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestDataCard from '@/components/RequestDataCard' import RequesDetailsCard from '@/components/RequestDetalilsCard' import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import { styledToast } from '@/utils/HelperUtil' import { @@ -21,6 +18,8 @@ export default function SessionSignMultiversxModal() { // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Ensure request and wallet are defined if (!requestEvent || !requestSession) { @@ -32,8 +31,9 @@ export default function SessionSignMultiversxModal() { const { request, chainId } = params // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (requestEvent) { + setIsLoadingApprove(true) const response = await approveMultiversxRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -41,16 +41,19 @@ export default function SessionSignMultiversxModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (requestEvent) { + setIsLoadingReject(true) const response = rejectMultiversxRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -58,12 +61,14 @@ export default function SessionSignMultiversxModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) return ( diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSignNearModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSignNearModal.tsx index 48e6a5e..4ec3451 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSignNearModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSignNearModal.tsx @@ -1,25 +1,24 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { transactions } from 'near-api-js' import { Divider, Text } from '@nextui-org/react' -import { Fragment } from 'react' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestDataCard from '@/components/RequestDataCard' import RequestDetailsCard from '@/components/RequestDetalilsCard' import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' import ModalStore from '@/store/ModalStore' import { approveNearRequest, rejectNearRequest } from '@/utils/NearRequestHandlerUtil' import { web3wallet } from '@/utils/WalletConnectUtil' import { NEAR_SIGNING_METHODS } from '@/data/NEARData' import { styledToast } from '@/utils/HelperUtil' -import ModalFooter from '@/components/ModalFooter' -import VerifyInfobox from '@/components/VerifyInfobox' import RequestModal from './RequestModal' +import { useCallback, useState } from 'react' export default function SessionSignNearModal() { // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Ensure request and wallet are defined if (!requestEvent || !requestSession) { @@ -142,8 +141,9 @@ export default function SessionSignNearModal() { } // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (requestEvent) { + setIsLoadingApprove(true) const response = await approveNearRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -151,16 +151,19 @@ export default function SessionSignNearModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (requestEvent) { + setIsLoadingReject(true) const response = rejectNearRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -168,12 +171,14 @@ export default function SessionSignNearModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) return ( diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSignPolkadotModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSignPolkadotModal.tsx index 2ae787f..a6d1a57 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSignPolkadotModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSignPolkadotModal.tsx @@ -1,23 +1,22 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { Divider, Text } from '@nextui-org/react' -import { Fragment } from 'react' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestDataCard from '@/components/RequestDataCard' import RequesDetailsCard from '@/components/RequestDetalilsCard' import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import { styledToast } from '@/utils/HelperUtil' import { approvePolkadotRequest, rejectPolkadotRequest } from '@/utils/PolkadotRequestHandlerUtil' import { web3wallet } from '@/utils/WalletConnectUtil' import RequestModal from './RequestModal' +import { useCallback, useState } from 'react' export default function SessionSignPolkadotModal() { // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Ensure request and wallet are defined if (!requestEvent || !requestSession) { @@ -29,8 +28,9 @@ export default function SessionSignPolkadotModal() { const { request, chainId } = params // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (requestEvent) { + setIsLoadingApprove(true) const response = await approvePolkadotRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -38,16 +38,19 @@ export default function SessionSignPolkadotModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (requestEvent) { + setIsLoadingReject(true) const response = rejectPolkadotRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -55,12 +58,14 @@ export default function SessionSignPolkadotModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) return ( diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSignSolanaModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSignSolanaModal.tsx index bd9e79d..5c1072a 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSignSolanaModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSignSolanaModal.tsx @@ -1,23 +1,22 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { Divider, Text } from '@nextui-org/react' -import { Fragment } from 'react' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestDataCard from '@/components/RequestDataCard' import RequesDetailsCard from '@/components/RequestDetalilsCard' import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import { styledToast } from '@/utils/HelperUtil' import { approveSolanaRequest, rejectSolanaRequest } from '@/utils/SolanaRequestHandlerUtil' import { web3wallet } from '@/utils/WalletConnectUtil' import RequestModal from './RequestModal' +import { useCallback, useState } from 'react' export default function SessionSignSolanaModal() { // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Ensure request and wallet are defined if (!requestEvent || !requestSession) { @@ -29,8 +28,9 @@ export default function SessionSignSolanaModal() { const { request, chainId } = params // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (requestEvent) { + setIsLoadingApprove(true) const response = await approveSolanaRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -38,16 +38,19 @@ export default function SessionSignSolanaModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (requestEvent) { + setIsLoadingReject(true) const response = rejectSolanaRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -55,12 +58,14 @@ export default function SessionSignSolanaModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) return ( diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSignTezosModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSignTezosModal.tsx index 853d7b2..0f3a036 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSignTezosModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSignTezosModal.tsx @@ -1,23 +1,22 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { Divider, Text } from '@nextui-org/react' -import { Fragment } from 'react' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestDataCard from '@/components/RequestDataCard' import RequesDetailsCard from '@/components/RequestDetalilsCard' import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import { styledToast } from '@/utils/HelperUtil' import { approveTezosRequest, rejectTezosRequest } from '@/utils/TezosRequestHandlerUtil' import { web3wallet } from '@/utils/WalletConnectUtil' import RequestModal from './RequestModal' +import { useCallback, useState } from 'react' export default function SessionSignTezosModal() { // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Ensure request and wallet are defined if (!requestEvent || !requestSession) { @@ -29,8 +28,9 @@ export default function SessionSignTezosModal() { const { request, chainId } = params // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (requestEvent) { + setIsLoadingApprove(true) const response = await approveTezosRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -38,16 +38,19 @@ export default function SessionSignTezosModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (requestEvent) { + setIsLoadingReject(true) const response = rejectTezosRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -55,12 +58,14 @@ export default function SessionSignTezosModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) return ( diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSignTronModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSignTronModal.tsx index f2f2701..0d76bc0 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSignTronModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSignTronModal.tsx @@ -1,23 +1,22 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { Divider, Text } from '@nextui-org/react' -import { Fragment } from 'react' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestDataCard from '@/components/RequestDataCard' import RequesDetailsCard from '@/components/RequestDetalilsCard' import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import { styledToast } from '@/utils/HelperUtil' import { approveTronRequest, rejectTronRequest } from '@/utils/TronRequestHandlerUtil' import { web3wallet } from '@/utils/WalletConnectUtil' import RequestModal from './RequestModal' +import { useCallback, useState } from 'react' export default function SessionSignTronModal() { // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Ensure request and wallet are defined if (!requestEvent || !requestSession) { @@ -29,8 +28,9 @@ export default function SessionSignTronModal() { const { request, chainId } = params // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (requestEvent) { + setIsLoadingApprove(true) const response = await approveTronRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -38,16 +38,19 @@ export default function SessionSignTronModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (requestEvent) { + setIsLoadingReject(true) const response = rejectTronRequest(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -55,12 +58,14 @@ export default function SessionSignTronModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) return ( diff --git a/advanced/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx b/advanced/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx index 7abf00b..0fada9f 100644 --- a/advanced/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx +++ b/advanced/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx @@ -1,23 +1,22 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { Divider, Text } from '@nextui-org/react' -import { Fragment } from 'react' -import ModalFooter from '@/components/ModalFooter' -import ProjectInfoCard from '@/components/ProjectInfoCard' import RequestDataCard from '@/components/RequestDataCard' import RequesDetailsCard from '@/components/RequestDetalilsCard' import RequestMethodCard from '@/components/RequestMethodCard' -import RequestModalContainer from '@/components/RequestModalContainer' -import VerifyInfobox from '@/components/VerifyInfobox' import ModalStore from '@/store/ModalStore' import { approveEIP155Request, rejectEIP155Request } from '@/utils/EIP155RequestHandlerUtil' import { getSignTypedDataParamsData, styledToast } from '@/utils/HelperUtil' import { web3wallet } from '@/utils/WalletConnectUtil' import RequestModal from './RequestModal' +import { useCallback, useState } from 'react' export default function SessionSignTypedDataModal() { // Get request and wallet data from store const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession + const [isLoadingApprove, setIsLoadingApprove] = useState(false) + const [isLoadingReject, setIsLoadingReject] = useState(false) // Ensure request and wallet are defined if (!requestEvent || !requestSession) { @@ -32,8 +31,9 @@ export default function SessionSignTypedDataModal() { const data = getSignTypedDataParamsData(request.params) // Handle approve action (logic varies based on request method) - async function onApprove() { + const onApprove = useCallback(async () => { if (requestEvent) { + setIsLoadingApprove(true) const response = await approveEIP155Request(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -41,16 +41,19 @@ export default function SessionSignTypedDataModal() { response }) } catch (e) { + setIsLoadingApprove(false) styledToast((e as Error).message, 'error') return } + setIsLoadingApprove(false) ModalStore.close() } - } + }, [requestEvent, topic]) // Handle reject action - async function onReject() { + const onReject = useCallback(async () => { if (requestEvent) { + setIsLoadingReject(true) const response = rejectEIP155Request(requestEvent) try { await web3wallet.respondSessionRequest({ @@ -58,12 +61,14 @@ export default function SessionSignTypedDataModal() { response }) } catch (e) { + setIsLoadingReject(false) styledToast((e as Error).message, 'error') return } + setIsLoadingReject(false) ModalStore.close() } - } + }, [requestEvent, topic]) return (