BigBlocks Docs
Components/Wallet

QuickDonateButton

A streamlined donation button for accepting Bitcoin SV donations with preset amounts and one-click processing

A streamlined donation button component that provides a frictionless experience for accepting Bitcoin SV donations with smart preset amounts, real-time validation, and comprehensive transaction tracking.

View Component Preview →

Installation

npx bigblocks add quick-donate-button

Import

import { QuickDonateButton } from 'bigblocks';

Props

PropTypeRequiredDefaultDescription
recipientAddressstringYes-Bitcoin address to receive donations
amountsnumber[]No[0.001, 0.005, 0.01]Preset BSV amounts for quick selection
defaultAmountnumberNoFirst amountDefault selected amount
onSuccess(txid: string) => voidNo-Callback when donation succeeds
onError(error: QuickDonationError) => voidNo-Callback when donation fails
labelstringNo'Donate'Button label text
compactbooleanNotrueUse compact display mode
classNamestringNo-Additional CSS classes

QuickDonationError Interface

interface QuickDonationError {
  code: 
    | 'INSUFFICIENT_FUNDS'        // Not enough BSV for donation
    | 'INVALID_ADDRESS'           // Malformed recipient address
    | 'AMOUNT_TOO_SMALL'          // Below minimum donation amount
    | 'AMOUNT_TOO_LARGE'          // Above maximum transaction limit
    | 'DAILY_LIMIT_EXCEEDED'      // Daily donation limit reached
    | 'RATE_LIMITED'              // Too many requests
    | 'RECIPIENT_BLOCKED';        // Recipient not allowed
  message: string;
  details?: {
    minimumAmount?: number;       // Minimum required amount
    maximumAmount?: number;       // Maximum allowed amount
    dailyLimit?: number;          // Daily limit amount
    dailyUsed?: number;           // Amount used today
    resetTime?: number;           // When limits reset
    available?: number;           // Available balance
    required?: number;            // Required amount
  };
}

Basic Usage

import { QuickDonateButton } from 'bigblocks';

export default function DonationSection() {
  return (
    <QuickDonateButton 
      recipientAddress="1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
      amounts={[0.001, 0.01, 0.1]}
      onSuccess={(txid) => {
        console.log('Donation sent! TxID:', txid);
      }}
    />
  );
}

Advanced Usage

Complete Donation Integration

import { QuickDonateButton } from 'bigblocks';
import { useState } from 'react';

export default function AdvancedDonation() {
  const [donationHistory, setDonationHistory] = useState<string[]>([]);
  const [isProcessing, setIsProcessing] = useState(false);

  const handleDonationSuccess = (txid: string) => {
    setDonationHistory(prev => [txid, ...prev]);
    setIsProcessing(false);
    
    // Track donation for analytics
    console.log('Donation successful:', txid);
    
    // Show success notification
    alert(`Thank you for your donation! Transaction: ${txid.slice(0, 8)}...`);
    
    // Optional: Navigate to success page
    // router.push(`/donation/success?txid=${txid}`);
  };

  const handleDonationError = (error: QuickDonationError) => {
    setIsProcessing(false);
    
    switch (error.code) {
      case 'INSUFFICIENT_FUNDS':
        alert(`Insufficient funds. You need ${error.details?.required} satoshis but only have ${error.details?.available}.`);
        break;
      case 'DAILY_LIMIT_EXCEEDED':
        alert(`Daily donation limit of ${error.details?.dailyLimit} satoshis exceeded. Limit resets at ${new Date(error.details?.resetTime || 0).toLocaleTimeString()}.`);
        break;
      case 'AMOUNT_TOO_SMALL':
        alert(`Minimum donation amount is ${error.details?.minimumAmount} satoshis.`);
        break;
      default:
        alert(`Donation failed: ${error.message}`);
    }
  };

  return (
    <div className="donation-section">
      <h2>Support Our Project</h2>
      <p>Your donations help us continue building amazing Bitcoin applications.</p>
      
      <QuickDonateButton 
        recipientAddress="1BitcoinDeveloperAddressHere..."
        amounts={[0.001, 0.005, 0.01, 0.05, 0.1]}
        defaultAmount={0.005}
        onSuccess={handleDonationSuccess}
        onError={handleDonationError}
        label="Support Development"
        compact={false}
        className="bg-gradient-to-r from-orange-500 to-red-500 text-white font-bold"
      />
      
      {donationHistory.length > 0 && (
        <div className="donation-history mt-4">
          <h3>Your Recent Donations</h3>
          <ul className="text-sm text-gray-600">
            {donationHistory.slice(0, 5).map((txid) => (
              <li key={txid}>
                <a 
                  href={`https://whatsonchain.com/tx/${txid}`}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="hover:underline"
                >
                  {txid.slice(0, 8)}...{txid.slice(-8)}
                </a>
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}

Smart Presets with Dynamic Amounts

import { QuickDonateButton } from 'bigblocks';
import { useEffect, useState } from 'react';

export default function SmartPresetDonation() {
  const [smartAmounts, setSmartAmounts] = useState<number[]>([0.001, 0.005, 0.01]);

  useEffect(() => {
    // Fetch smart presets based on recipient and donor history
    const fetchSmartPresets = async () => {
      try {
        const response = await fetch('/api/wallet/quick-donate/presets?currency=BSV&recipient=1BitcoinAddress...');
        const data = await response.json();
        
        if (data.presets) {
          const amounts = data.presets.map((preset: any) => 
            parseFloat(preset.amountBSV)
          );
          setSmartAmounts(amounts);
        }
      } catch (error) {
        console.error('Failed to fetch smart presets:', error);
      }
    };

    fetchSmartPresets();
  }, []);

  return (
    <div className="smart-donation">
      <h3>Smart Donation Amounts</h3>
      <p>Amounts personalized based on your donation history and recipient preferences.</p>
      
      <QuickDonateButton 
        recipientAddress="1BitcoinRecipientAddress..."
        amounts={smartAmounts}
        onSuccess={(txid) => {
          console.log('Smart donation successful:', txid);
          // Update user's donation profile for better future recommendations
        }}
        className="border-2 border-blue-500 hover:bg-blue-50"
      />
    </div>
  );
}

Charity Campaign Integration

import { QuickDonateButton } from 'bigblocks';
import { useState, useEffect } from 'react';

interface CampaignInfo {
  name: string;
  goal: number;
  raised: number;
  description: string;
  endDate: string;
}

export default function CharityCampaign() {
  const [campaign, setCampaign] = useState<CampaignInfo | null>(null);
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    // Fetch campaign information
    const fetchCampaign = async () => {
      // This would typically come from your API
      setCampaign({
        name: "Bitcoin Education Fund",
        goal: 10, // 10 BSV
        raised: 6.5, // 6.5 BSV raised so far
        description: "Help us educate developers about Bitcoin applications",
        endDate: "2025-12-31"
      });
    };

    fetchCampaign();
  }, []);

  useEffect(() => {
    if (campaign) {
      setProgress((campaign.raised / campaign.goal) * 100);
    }
  }, [campaign]);

  const handleCampaignDonation = (txid: string) => {
    console.log('Campaign donation:', txid);
    
    // Update campaign progress (in real app, this would come from backend)
    if (campaign) {
      setCampaign(prev => prev ? {
        ...prev,
        raised: prev.raised + 0.001 // Assume small donation for demo
      } : null);
    }
    
    // Send campaign donation tracking
    fetch('/api/campaigns/track-donation', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        campaignId: 'bitcoin-education-fund',
        txid,
        timestamp: Date.now()
      })
    });
  };

  if (!campaign) return <div>Loading campaign...</div>;

  return (
    <div className="charity-campaign">
      <div className="campaign-info mb-6">
        <h2 className="text-2xl font-bold">{campaign.name}</h2>
        <p className="text-gray-600 mb-4">{campaign.description}</p>
        
        <div className="progress-section mb-4">
          <div className="flex justify-between text-sm mb-2">
            <span>{campaign.raised} BSV raised</span>
            <span>{campaign.goal} BSV goal</span>
          </div>
          <div className="w-full bg-gray-200 rounded-full h-2.5">
            <div 
              className="bg-green-600 h-2.5 rounded-full transition-all duration-500"
              style={{ width: `${Math.min(progress, 100)}%` }}
            ></div>
          </div>
          <p className="text-sm text-gray-500 mt-2">
            {Math.round(progress)}% complete • Ends {new Date(campaign.endDate).toLocaleDateString()}
          </p>
        </div>
      </div>
      
      <QuickDonateButton 
        recipientAddress="1CharityBitcoinAddress..."
        amounts={[0.001, 0.01, 0.1, 0.5]}
        defaultAmount={0.01}
        onSuccess={handleCampaignDonation}
        onError={(error) => {
          console.error('Campaign donation failed:', error);
          alert('Donation failed. Please try again.');
        }}
        label="Donate to Campaign"
        className="w-full bg-green-600 hover:bg-green-700 text-white font-semibold py-3"
      />
    </div>
  );
}

Common Patterns

Multi-Recipient Donation Dashboard

import { QuickDonateButton } from 'bigblocks';

const recipients = [
  {
    name: "Open Source Developer",
    address: "1Developer1Address...",
    description: "Building Bitcoin tools",
    category: "development",
    amounts: [0.001, 0.01, 0.1]
  },
  {
    name: "Bitcoin Charity",
    address: "1Charity1Address...",
    description: "Helping those in need",
    category: "charity", 
    amounts: [0.01, 0.1, 1.0]
  },
  {
    name: "Content Creator",
    address: "1Creator1Address...",
    description: "Educational Bitcoin content",
    category: "creator",
    amounts: [0.001, 0.005, 0.01]
  }
];

export default function DonationDashboard() {
  const handleDonation = (recipient: string, txid: string) => {
    console.log(`Donation to ${recipient}: ${txid}`);
    
    // Track donation analytics
    fetch('/api/analytics/donation', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        recipient,
        txid,
        source: 'dashboard',
        timestamp: Date.now()
      })
    });
  };

  return (
    <div className="donation-dashboard">
      <h1>Support the Bitcoin Ecosystem</h1>
      
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
        {recipients.map((recipient) => (
          <div key={recipient.address} className="recipient-card p-6 border rounded-lg">
            <h3 className="font-bold text-lg">{recipient.name}</h3>
            <p className="text-gray-600 mb-2">{recipient.description}</p>
            <span className="inline-block bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded mb-4">
              {recipient.category}
            </span>
            
            <QuickDonateButton 
              recipientAddress={recipient.address}
              amounts={recipient.amounts}
              onSuccess={(txid) => handleDonation(recipient.name, txid)}
              label="Support"
              className="w-full"
            />
          </div>
        ))}
      </div>
    </div>
  );
}

Subscription-Style Recurring Donations

import { QuickDonateButton } from 'bigblocks';
import { useState } from 'react';

export default function RecurringDonation() {
  const [isRecurring, setIsRecurring] = useState(false);
  const [recurringAmount, setRecurringAmount] = useState(0.01);

  const handleRecurringDonation = async (txid: string) => {
    console.log('Initial recurring donation:', txid);
    
    if (isRecurring) {
      // Set up recurring donation schedule
      try {
        await fetch('/api/wallet/recurring-donations', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            recipientAddress: "1RecurringRecipient...",
            amount: recurringAmount * 100000000, // Convert to satoshis
            frequency: 'monthly',
            startDate: Date.now(),
            initialTxid: txid
          })
        });
        
        alert('Recurring donation set up successfully!');
      } catch (error) {
        console.error('Failed to set up recurring donation:', error);
      }
    }
  };

  return (
    <div className="recurring-donation">
      <h3>Monthly Support</h3>
      
      <div className="recurring-options mb-4">
        <label className="flex items-center">
          <input 
            type="checkbox"
            checked={isRecurring}
            onChange={(e) => setIsRecurring(e.target.checked)}
            className="mr-2"
          />
          Make this a monthly recurring donation
        </label>
      </div>
      
      <QuickDonateButton 
        recipientAddress="1RecurringRecipient..."
        amounts={[0.01, 0.05, 0.1]}
        defaultAmount={recurringAmount}
        onSuccess={handleRecurringDonation}
        label={isRecurring ? "Start Monthly Support" : "One-time Donation"}
        className={isRecurring ? "bg-purple-600 hover:bg-purple-700" : ""}
      />
      
      {isRecurring && (
        <p className="text-sm text-gray-600 mt-2">
          You'll be charged {recurringAmount} BSV monthly. Cancel anytime in settings.
        </p>
      )}
    </div>
  );
}

Authentication Requirements

The QuickDonateButton requires Bitcoin authentication context for wallet operations:

import { 
  BitcoinAuthProvider, 
  BitcoinQueryProvider, 
  QuickDonateButton 
} from 'bigblocks';

function App() {
  return (
    <BitcoinQueryProvider>
      <BitcoinAuthProvider config={{ 
        apiUrl: '/api',
        walletMode: 'integrated' // Enables wallet features
      }}>
        <QuickDonateButton 
          recipientAddress="1BitcoinAddress..."
        />
      </BitcoinAuthProvider>
    </BitcoinQueryProvider>
  );
}

API Integration

The QuickDonateButton integrates with several backend endpoints for comprehensive donation processing:

Core Donation Endpoints

// Send quick donation
POST /api/wallet/quick-donate
{
  recipientAddress: string;
  amount: number; // satoshis
  message?: string;
  source?: string;
  metadata?: {
    page?: string;
    context?: string;
    campaign?: string;
  };
}

// Response includes transaction details and updated balance
{
  success: boolean;
  txid: string;
  quickDonation: {
    id: string;
    amount: number;
    recipient: string;
    status: 'pending' | 'confirmed';
    // ... full donation details
  };
  balance: {
    remaining: number;
    canDonateAgain: boolean;
  };
}

Smart Presets API

// Get personalized donation amounts
GET /api/wallet/quick-donate/presets?currency=BSV&recipient=<address>

// Returns optimized amounts based on:
// - Recipient category (charity, development, creator)
// - Donor's previous donation history  
// - Current BSV market price
// - Donor's wallet balance
{
  presets: [
    {
      amount: number;
      amountBSV: string;
      amountUSD?: string;
      label: string; // "Small", "Medium", "Large"
      recommended?: boolean;
    }
  ];
  recipient?: {
    name?: string;
    verified?: boolean;
    category?: string;
  };
  limits: {
    minimum: number;
    maximum: number;
    dailyLimit?: number;
  };
}

Validation and Security

// Validate donation before processing
POST /api/wallet/quick-donate/validate
{
  recipientAddress: string;
  amount: number;
}

// Comprehensive validation response
{
  valid: boolean;
  validation: {
    address: {
      valid: boolean;
      type?: 'p2pkh' | 'p2sh' | 'p2wpkh';
      network: 'mainnet' | 'testnet';
    };
    amount: {
      valid: boolean;
      withinLimits: boolean;
      belowBalance: boolean;
      aboveDust: boolean;
    };
    fees: {
      estimated: number;
      total: number;
      affordable: boolean;
    };
  };
  warnings?: string[];
  suggestions?: {
    adjustedAmount?: number;
    feeOptimization?: string;
  };
}

Real-time Updates

// Server-Sent Events for donation updates
GET /api/wallet/quick-donate/stream

Events:
- donation_sent: { txid: string, amount: number, recipient: string }
- donation_confirmed: { txid: string, confirmations: number }
- balance_updated: { balance: number, canDonate: boolean }
- daily_limit_reached: { limit: number, resetTime: number }

Error Handling

Comprehensive Error Management

import { QuickDonateButton } from 'bigblocks';

export default function RobustDonationHandler() {
  const handleDonationError = (error: QuickDonationError) => {
    switch (error.code) {
      case 'INSUFFICIENT_FUNDS':
        // Show user their balance and suggest smaller amount
        console.log(`Need ${error.details?.required} satoshis, have ${error.details?.available}`);
        showBalanceModal(error.details);
        break;
        
      case 'AMOUNT_TOO_SMALL':
        // Suggest minimum amount
        console.log(`Minimum donation: ${error.details?.minimumAmount} satoshis`);
        suggestMinimumAmount(error.details?.minimumAmount);
        break;
        
      case 'DAILY_LIMIT_EXCEEDED':
        // Show limit info and reset time
        const resetTime = new Date(error.details?.resetTime || 0);
        console.log(`Daily limit exceeded. Resets at ${resetTime.toLocaleTimeString()}`);
        showLimitExceededModal(error.details);
        break;
        
      case 'RATE_LIMITED':
        // Show retry countdown
        console.log('Too many donation attempts. Please wait.');
        showRateLimitWarning();
        break;
        
      case 'INVALID_ADDRESS':
        // Show address validation error
        console.log('Invalid recipient address');
        showAddressError();
        break;
        
      default:
        // Generic error handler
        console.error('Unknown donation error:', error);
        showGenericError(error.message);
    }
  };

  return (
    <QuickDonateButton 
      recipientAddress="1BitcoinAddress..."
      amounts={[0.001, 0.01, 0.1]}
      onError={handleDonationError}
      onSuccess={(txid) => {
        console.log('Donation successful:', txid);
        showSuccessNotification(txid);
      }}
    />
  );
}

Error Recovery Patterns

import { QuickDonateButton } from 'bigblocks';
import { useState } from 'react';

export default function ErrorRecoveryDonation() {
  const [lastError, setLastError] = useState<QuickDonationError | null>(null);
  const [suggestedAmount, setSuggestedAmount] = useState<number | null>(null);

  const handleError = (error: QuickDonationError) => {
    setLastError(error);
    
    // Auto-suggest recovery actions
    if (error.code === 'AMOUNT_TOO_SMALL' && error.details?.minimumAmount) {
      setSuggestedAmount(error.details.minimumAmount / 100000000); // Convert to BSV
    } else if (error.code === 'INSUFFICIENT_FUNDS' && error.details?.available) {
      // Suggest 90% of available balance to account for fees
      const maxSafe = (error.details.available * 0.9) / 100000000;
      setSuggestedAmount(maxSafe);
    }
  };

  const retryWithSuggestedAmount = () => {
    setLastError(null);
    setSuggestedAmount(null);
    // Component will re-render with new suggested amount
  };

  return (
    <div className="error-recovery-donation">
      <QuickDonateButton 
        recipientAddress="1BitcoinAddress..."
        amounts={suggestedAmount ? [suggestedAmount] : [0.001, 0.01, 0.1]}
        onError={handleError}
        onSuccess={() => {
          setLastError(null);
          setSuggestedAmount(null);
        }}
      />
      
      {lastError && (
        <div className="error-recovery mt-4 p-4 bg-red-50 border border-red-200 rounded">
          <h4 className="font-semibold text-red-800">Donation Failed</h4>
          <p className="text-red-600">{lastError.message}</p>
          
          {suggestedAmount && (
            <div className="mt-2">
              <p className="text-sm text-red-600">
                Suggested amount: {suggestedAmount} BSV
              </p>
              <button 
                onClick={retryWithSuggestedAmount}
                className="mt-2 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700"
              >
                Retry with {suggestedAmount} BSV
              </button>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

Performance Optimization

Preset Caching Strategy

import { QuickDonateButton } from 'bigblocks';
import { useState, useEffect, useMemo } from 'react';

export default function OptimizedDonation() {
  const [cachedPresets, setCachedPresets] = useState<Map<string, any>>(new Map());
  
  const recipientAddress = "1BitcoinAddress...";
  
  // Memoized preset loading with cache
  const presets = useMemo(() => {
    const cacheKey = `${recipientAddress}:BSV`;
    
    if (cachedPresets.has(cacheKey)) {
      const cached = cachedPresets.get(cacheKey);
      // Check if cache is still valid (5 minute TTL)
      if (Date.now() - cached.timestamp < 300000) {
        return cached.presets;
      }
    }
    
    // Load fresh presets
    fetch(`/api/wallet/quick-donate/presets?currency=BSV&recipient=${recipientAddress}`)
      .then(res => res.json())
      .then(data => {
        setCachedPresets(prev => new Map(prev).set(cacheKey, {
          presets: data.presets.map((p: any) => parseFloat(p.amountBSV)),
          timestamp: Date.now()
        }));
      })
      .catch(console.error);
    
    // Return default while loading
    return [0.001, 0.01, 0.1];
  }, [recipientAddress, cachedPresets]);

  return (
    <QuickDonateButton 
      recipientAddress={recipientAddress}
      amounts={presets}
    />
  );
}

Security Considerations

Rate Limiting and Abuse Prevention

The QuickDonateButton implements several security measures:

  • Transaction Rate Limiting: Maximum 20 donations per hour per user
  • Daily Spending Limits: Configurable daily donation limits (default: 1 BSV)
  • Address Validation: Real-time Bitcoin address format validation
  • Amount Validation: Enforced minimum (dust limit) and maximum amounts
  • Recipient Verification: Optional recipient verification system

Safe Donation Practices

import { QuickDonateButton } from 'bigblocks';

export default function SecureDonation() {
  const verifyRecipient = async (address: string) => {
    try {
      const response = await fetch(`/api/wallet/recipients/${address}`);
      const data = await response.json();
      
      return {
        verified: data.recipient?.verified || false,
        trustScore: data.trustScore || 0,
        category: data.recipient?.category
      };
    } catch {
      return { verified: false, trustScore: 0 };
    }
  };

  const handleSecureDonation = async (txid: string) => {
    // Log successful donation for audit trail
    await fetch('/api/audit/donation', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        txid,
        timestamp: Date.now(),
        source: 'quick-donate-button',
        userAgent: navigator.userAgent
      })
    });
    
    console.log('Secure donation completed:', txid);
  };

  return (
    <div className="secure-donation">
      <div className="security-notice mb-4 p-3 bg-yellow-50 border border-yellow-200 rounded">
        <p className="text-sm text-yellow-800">
          🔒 All donations are processed securely using Bitcoin signatures. 
          Verify recipient addresses before donating.
        </p>
      </div>
      
      <QuickDonateButton 
        recipientAddress="1VerifiedRecipientAddress..."
        amounts={[0.001, 0.01, 0.1]}
        onSuccess={handleSecureDonation}
        onError={(error) => {
          // Log security-related errors
          if (error.code === 'RECIPIENT_BLOCKED') {
            console.warn('Attempted donation to blocked recipient');
          }
        }}
      />
    </div>
  );
}

Troubleshooting

Common Issues

Button doesn't respond to clicks

  • Ensure BitcoinAuthProvider is properly configured
  • Check that user has sufficient balance for minimum donation
  • Verify recipient address format is valid

Donations fail with "insufficient funds"

  • Check user's actual BSV balance
  • Account for transaction fees (~0.0001 BSV)
  • Verify no daily spending limits are exceeded

Preset amounts not loading

  • Check API endpoint /api/wallet/quick-donate/presets is accessible
  • Verify recipient address is valid
  • Check network connectivity for preset fetching

Daily limit errors

  • Daily limits reset at midnight UTC
  • Check user's donation history for the current day
  • Limits can be configured per user in admin settings

Debug Mode

import { QuickDonateButton } from 'bigblocks';

export default function DebugDonation() {
  const debugDonation = (txid: string) => {
    console.log('Debug donation success:', {
      txid,
      timestamp: new Date().toISOString(),
      userAgent: navigator.userAgent,
      recipientAddress: '1BitcoinAddress...'
    });
  };

  const debugError = (error: QuickDonationError) => {
    console.error('Debug donation error:', {
      code: error.code,
      message: error.message,
      details: error.details,
      timestamp: new Date().toISOString()
    });
  };

  return (
    <div className="debug-donation">
      <h3>Debug Mode Donation</h3>
      <QuickDonateButton 
        recipientAddress="1BitcoinAddress..."
        amounts={[0.001, 0.01, 0.1]}
        onSuccess={debugDonation}
        onError={debugError}
        className="border-2 border-gray-300"
      />
    </div>
  );
}

API Reference

QuickDonateButton Component

interface QuickDonateButtonProps {
  recipientAddress: string;
  amounts?: number[];
  defaultAmount?: number;
  onSuccess?: (txid: string) => void;
  onError?: (error: QuickDonationError) => void;
  label?: string;
  compact?: boolean;
  className?: string;
}

Advanced Usage with React Query

import { useQuery, useMutation } from '@tanstack/react-query';
import { QuickDonateButton } from 'bigblocks';

function QuickDonateWithQuery() {
  // Query for smart presets
  const { data: presets } = useQuery({
    queryKey: ['donation-presets', recipientAddress],
    queryFn: () => fetch(`/api/wallet/quick-donate/presets?currency=BSV&recipient=${recipientAddress}`).then(res => res.json()),
    staleTime: 5 * 60 * 1000, // 5 minutes
    refetchOnWindowFocus: false
  });

  // Mutation for donation processing
  const donationMutation = useMutation({
    mutationFn: (donationData: { recipientAddress: string; amount: number }) =>
      fetch('/api/wallet/quick-donate', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(donationData)
      }).then(res => res.json()),
    onSuccess: (data) => {
      console.log('Donation processed:', data.txid);
    },
    onError: (error) => {
      console.error('Donation failed:', error);
    }
  });

  const amounts = presets?.presets.map((p: any) => parseFloat(p.amountBSV)) || [0.001, 0.01, 0.1];

  return (
    <QuickDonateButton 
      recipientAddress={recipientAddress}
      amounts={amounts}
      onSuccess={(txid) => console.log('Success:', txid)}
      onError={(error) => console.error('Error:', error)}
    />
  );
}