Skip to Content
Welcome to RitoSwap's documentation!
DAppSmart Contract UIButton Section

ButtonSection

The ButtonSection component serves as the primary action interface for all NFT-related operations in RitoSwap. This intelligent component adapts its presentation based on wallet connection status, NFT ownership, and token gate usage, providing users with contextually appropriate actions at each stage of their journey. Through sophisticated state management and transaction orchestration, it transforms complex blockchain operations into simple button clicks while maintaining comprehensive error handling and user feedback.

Component Architecture

ButtonSection implements a reactive architecture that continuously adapts to changing blockchain state. The component orchestrates multiple wagmi hooks for transaction management, integrates with the network checking system to prevent wrong-chain transactions, and provides real-time feedback through both the ProcessingModal component and toast notifications. This multi-layered approach ensures users always understand what actions are available and receive clear feedback during asynchronous blockchain operations.

State-Based UI Adaptation

The component renders different interfaces based on four primary states:

StateConditionsUI Elements
Not Connected!isConnectedConnectWrapper (wallet connection button)
No NFTisConnected && !hasNFTMint NFT button
Unused NFTisConnected && hasNFT && !hasUsedTokenGateToken Gate link + Burn button
Used NFTisConnected && hasNFT && hasUsedTokenGateBurn button only

This adaptive approach ensures users only see relevant actions, reducing cognitive load and preventing invalid operations.

Interactive Demo

Use the dropdown to change states

Props and Interface

ButtonSection follows the zero-configuration pattern established by other components:

export default function ButtonSection() { // All data from hooks and stores - no props required }

This design maintains consistency across the component hierarchy and simplifies integration.

Transaction Management

The component implements comprehensive transaction management using wagmi hooks:

Write Contract Hooks

const { writeContract: mint, data: mintHash, isPending: isMinting, error: mintError, reset: resetMint } = useWriteContract() const { writeContract: burn, data: burnHash, isPending: isBurning, error: burnError, reset: resetBurn } = useWriteContract()

Each hook provides complete transaction lifecycle management from initiation through confirmation.

Transaction Confirmation

The component monitors transaction confirmations to trigger appropriate state updates:

const { isLoading: isMintConfirming, isSuccess: isMintSuccess } = useWaitForTransactionReceipt({ hash: mintHash, query: { enabled: !!mintHash }, })

This pattern ensures the UI accurately reflects blockchain state rather than optimistically updating.

Network Validation

Before executing any transaction, ButtonSection validates the user is on the correct network:

const handleMint = () => { setLoading(true) executeWithNetworkCheck(() => { mint({ address: KEY_TOKEN_ADDRESS, abi: fullKeyTokenAbi, functionName: 'mint', }) if (displayUri) openWallet() }) }

The executeWithNetworkCheck wrapper prevents transactions on wrong chains, protecting users from costly mistakes.

Mobile Wallet Integration

The component includes special handling for mobile wallet interactions:

if (displayUri) openWallet()

When a WalletConnect URI is available and the user is on mobile, the component automatically triggers the wallet deep link after initiating transactions. This reduces friction for mobile users who would otherwise need to manually switch to their wallet app.

Success Handling

ButtonSection implements a sophisticated success handling flow that ensures proper state updates and user feedback:

Deduplication Logic

const [lastMintHash, setLastMintHash] = useState<string | null>(null) const [lastBurnHash, setLastBurnHash] = useState<string | null>(null) useEffect(() => { if (isMintSuccess && mintHash && mintHash !== lastMintHash) { setLastMintHash(mintHash) // Handle success only once per transaction } }, [isMintSuccess, mintHash])

This pattern prevents duplicate success handlers when effects re-run due to dependency changes.

Success Flow

Step 1: Transaction Confirmation

Wait for blockchain confirmation via useWaitForTransactionReceipt.

Step 2: User Notification

Display toast notification and trigger browser notification if permissions granted.

Step 3: State Refresh Delay

Wait 2 seconds to ensure blockchain state has propagated to RPC nodes.

Step 4: Force Data Refresh

Call forceRefresh() to update NFT ownership data from blockchain.

Step 5: Reset Transaction State

Clear loading state and reset wagmi hooks for future transactions.

Error Handling

The component implements comprehensive error handling for all failure scenarios:

useEffect(() => { if (mintError) { toast.error(`Failed to mint NFT: ${mintError.message}`) setLoading(false) resetMint() } }, [mintError, setLoading, resetMint])

Error messages are extracted and presented in user-friendly format through toast notifications, while the component state resets to allow retry attempts.

ProcessingModal Integration with Transaction Hash Passing

During transactions, ButtonSection displays the ProcessingModal to guide users through the transaction process. A key feature of this integration is the ability to pass transaction hashes to the modal, enabling users to track their transactions on block explorers:

<ProcessingModal isVisible={isProcessing} onCancel={handleModalCancel} transactionHash={mintHash || burnHash} // Pass current transaction hash />

Transaction Hash Management

The component intelligently determines which transaction hash to pass based on the current operation:

const isProcessing = isMinting || isBurning || isMintConfirming || isBurnConfirming const transactionHash = mintHash || burnHash // Current transaction hash

This approach ensures that the ProcessingModal always receives the relevant transaction hash, whether the user is minting or burning an NFT. The hash becomes available immediately after the transaction is submitted to the blockchain, before confirmation completes.

Purpose of Transaction Hash Passing

The transaction hash serves multiple important purposes in the user experience. It provides transparency by allowing users to see their transaction on a block explorer while waiting for confirmation. It enables debugging in development environments where Blockscout provides detailed transaction information. It offers reassurance to users who can verify their transaction is being processed by the network. Finally, it maintains context by keeping users informed without requiring them to leave the application.

The transaction hash is passed as soon as it’s available from the blockchain, typically within seconds of initiating the transaction. This immediate feedback transforms an opaque waiting period into a transparent process where users can track progress in real-time.

The modal’s cancel button allows users to reset component state if transactions become stuck:

const handleModalCancel = async () => { resetMint() resetBurn() setLoading(false) await forceRefresh() }
⚠️

The cancel button doesn’t actually cancel blockchain transactions - it only resets the UI state. Users must still clear pending transactions in their wallet if needed. The transaction will continue processing on the blockchain regardless of UI state.

Animation and Styling

ButtonSection implements sophisticated animations for smooth state transitions:

Button State Animations

.mintButton.processing::before, .burnButton.processing::before { content: ''; position: absolute; animation: waveSlide 2s ease-in-out infinite; }

The wave animation provides visual feedback during transaction processing without being distracting.

Transition Effects

.container { opacity: 1; transition: opacity 0.3s ease-in-out; } .container.transitioning { opacity: 0; }

Fade transitions between states prevent jarring button swaps.

Hydration Safety

The component implements careful hydration handling to prevent SSR mismatches:

const [isHydrated, setIsHydrated] = useState(false) useEffect(() => { const timer = setTimeout(() => setIsHydrated(true), 50) return () => clearTimeout(timer) }, []) if (!isHydrated || renderState === 'loading') { return ( <div className={styles.container}> <button className={styles.loadingButton} disabled> Loading... </button> </div> ) }

This approach ensures consistent server and client rendering while providing immediate visual feedback.

Store Integration

ButtonSection integrates with multiple stores for state management:

Store/HookData UsedPurpose
useAccountisConnectedDetermines if wallet is connected
NFT StorehasNFT, hasUsedTokenGate, tokenId, setLoading, isLoadingNFT ownership state and loading management
Wallet Connect StoreopenWallet, displayUriMobile wallet deep linking
useNFTDataforceRefreshTrigger data updates after transactions

Notification Integration

The component triggers both toast and browser notifications for important events:

toast.success('NFT minted successfully!') setTimeout(() => { NFTNotifications.minted() }, 100)

The delay ensures notification permissions are ready before attempting to send browser notifications.

Performance Optimizations

ButtonSection implements several performance optimizations:

Hydration Timer Cleanup - The initial hydration timeout is properly cleaned up to prevent memory leaks during component unmount.

Conditional Rendering - Components only render when in appropriate states, reducing React reconciliation work.

Transaction Deduplication - Success handlers only fire once per unique transaction hash.

Store Subscriptions - Components subscribe only to the specific store fields they need, minimizing re-renders when unrelated state changes.

Responsive Design

The component adapts its layout for mobile devices:

@media (max-width: 768px) { .container { flex-direction: column; gap: 0.8rem; min-height: 140px; /* Taller for vertical layout */ } .mintButton, .gateButton, .burnButton { width: 100%; max-width: 300px; } }

Buttons stack vertically on mobile while maintaining appropriate touch targets.

Testing Strategies

Testing ButtonSection requires extensive mocking of blockchain interactions:

// Mock transaction flow vi.mock('wagmi', () => ({ useWriteContract: vi.fn(() => ({ writeContract: mockWriteContract, data: '0x123', isPending: false, error: null, reset: vi.fn() })), useWaitForTransactionReceipt: vi.fn(() => ({ isLoading: false, isSuccess: true })) }))

Key test scenarios include successful minting and burning flows, error handling and recovery, state transitions between different ownership states, mobile wallet deep linking behavior, and transaction hash passing to ProcessingModal.

Common Integration Patterns

ButtonSection is typically placed below the NFT visualization:

function MintInterface() { return ( <> <TokenStatus /> <NFTScreen /> <ButtonSection /> {/* Actions at bottom */} </> ) }

This arrangement creates a natural flow from status to visualization to actions.

Customization Options

The component can be extended for additional functionality:

Additional Actions

New buttons can be added for extended functionality:

if (hasNFT && !isListed) { return <button onClick={handleList}>List on Marketplace</button> }

Custom Contract Functions

The pattern can be extended to call other contract functions:

const handleTransfer = () => { executeWithNetworkCheck(() => { transfer({ address: KEY_TOKEN_ADDRESS, abi: fullKeyTokenAbi, functionName: 'transferFrom', args: [address, recipientAddress, tokenId] }) }) }

Alternative Styling

The modular CSS allows complete visual customization while maintaining functionality.

Best Practices

When working with ButtonSection or similar transaction components:

Always Validate Network - Never skip network validation to prevent wrong-chain transactions.

Provide Clear Feedback - Use both toast and modal feedback for transaction states, including transaction hashes for transparency.

Handle All Error Cases - Implement error handling for every possible failure scenario.

Test Mobile Flows - Always test wallet deep linking on actual mobile devices.

Respect Processing States - Disable buttons during transactions to prevent double-spending attempts.

Pass Transaction Context - Always forward transaction hashes to feedback components for user transparency.

Troubleshooting Guide

IssueCommon CauseSolution
Buttons don’t appearHydration mismatchEnsure hydration safety logic
Transaction won’t completeWrong networkCheck network validation
Multiple success toastsEffect re-runsImplement hash deduplication
State doesn’t update after mintInsufficient delayIncrease refresh delay
No explorer link in modalHash not passedEnsure transactionHash prop is set

Summary

ButtonSection exemplifies best practices for blockchain transaction interfaces in React applications. Through its adaptive UI, comprehensive transaction management, mobile optimization, and extensive error handling, it transforms complex Web3 operations into intuitive user interactions. The component’s integration of network validation, processing feedback with transaction transparency, and notification systems creates a professional experience that guides users through every step of NFT ownership. The ability to pass transaction hashes to the ProcessingModal for block explorer integration demonstrates the component’s commitment to transparency and user empowerment. While currently optimized for minting and burning operations, its patterns provide a solid foundation for extending functionality to support additional blockchain interactions while maintaining the same level of polish and user experience.