> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phoenix.market/llms.txt
> Use this file to discover all available pages before exploring further.

# React Component Integration

> Learn how to integrate Phoenix using our pre-built React component

Follow these steps to integrate using our pre-built React component.

## Step 1: Obtain Access Token

<AccordionGroup>
  <Accordion title="Obtaining Access Token">
    Before using the Phoenix component, you need to obtain an access token from your backend.

    ```tsx theme={null}
    // Example of fetching the access token from your backend
    const [accessToken, setAccessToken] = useState('');

    useEffect(() => {
      // Replace with your actual backend endpoint that implements the token generation
      fetch('/api/token')
        .then(response => response.json())
        .then(data => setAccessToken(data.access_token))
        .catch(error => console.error('Error fetching access token:', error));
    }, []);
    ```

    See the [Obtaining Access Token](/api-reference/access-token) page for detailed instructions on setting up the backend endpoint.
  </Accordion>
</AccordionGroup>

<Note>
  This is example code for obtaining an access token. You will need to adapt the endpoint URL and request format based on your specific backend implementation. Refer to the [Obtaining Access Token](/api-reference/access-token) page for a complete example of setting up a backend service.
</Note>

## Step 2: Download the Component

You can view the component code or download it directly:

<AccordionGroup>
  <Accordion title="View Component Code">
    ```tsx PhoenixPayment.tsx theme={null}
    import React, { useEffect, useRef } from 'react';

    interface PhoenixPaymentProps {
      // Required parameters
      walletAddress: string;
      amount: string;
      accessToken: string; // Access token from your backend
      onClose: () => void;
      onComplete: (success: boolean, transactionId?: string, data?: any) => void;
      onDone?: () => void; // New callback for handling done events
      onOrderCreated?: (data: any) => void; // Callback for handling order creation
      theme?: 'light' | 'dark'; // Optional theme parameter
    }

    export const PhoenixPayment: React.FC<PhoenixPaymentProps> = ({
      walletAddress,
      amount,
      accessToken,
      onClose,
      onComplete,
      onDone,
      onOrderCreated,
      theme,
    }) => {
      const iframeRef = useRef<HTMLIFrameElement>(null);

      useEffect(() => {
        // Handle messages from the iframe
        const handleMessage = (event: MessageEvent) => {
          // Verify origin for security
          if (event.origin !== 'https://app-partner.phoenix.market') return;
          
          // Handle transaction success message
          if (event.data?.type === 'TRANSACTION_SUCCESS') {
            const { amount, token, chain, walletAddress, sendAmount, transactionHash, basescanLink } = event.data.data;
            onComplete(true, transactionHash, { 
              amount, token, chain, walletAddress, sendAmount, transactionHash, basescanLink 
            });
          }
          // Handle order created message
          else if (event.data?.type === 'ORDER_CREATED') {
            const { order_id, ...data } = event.data.data;
            console.log('Order created:', event.data.data);
            
            if (onOrderCreated) {
              onOrderCreated({ order_id, data });
            }
          }
          // Handle cancel message
          else if (event.data?.type === 'CANCEL') {
            console.log('Payment canceled by user');
            onClose();
          }
          // Handle open explorer URL message
          else if (event.data?.type === 'OPEN_EXPLORER_URL') {
            const url = event.data.url;
            console.log('Opening explorer URL:', url);
            
            // Always open in a new tab
            window.open(url, '_blank');
          }
          // Handle done message
          else if (event.data?.type === 'USER_DONE') {
            console.log('Payment process completed');
            
            if (onDone) {
              onDone();
            } else {
              // Default behavior: close the window
              onClose();
            }
          }
        };

        window.addEventListener('message', handleMessage);
        
        // Clean up
        return () => {
          window.removeEventListener('message', handleMessage);
        };
      }, [onComplete, onClose, onDone, onOrderCreated]);

      // Build iframe URL with all parameters
      const getIframeUrl = () => {
        let url = `https://app-partner.phoenix.market/?address=${walletAddress}&amount=${amount}&access_token=${accessToken}`;
        if (theme) {
          url += `&theme=${theme}`;
        }
        return url;
      };

      return (
        <div className="phoenix-payment-container">
          <div className="payment-overlay">
            <div className="payment-modal">
              <button 
                className="close-button" 
                onClick={onClose}
                aria-label="Close payment window"
              >
                &times;
              </button>
              <iframe
                ref={iframeRef}
                src={getIframeUrl()}
                className="teller-iframe"
                title="Phoenix Payment"
                allow="clipboard-write"
              />
            </div>
          </div>
          <style>{`
            .phoenix-payment-container {
              position: fixed;
              top: 0;
              left: 0;
              width: 100%;
              height: 100%;
              z-index: 1000;
            }
            
            .payment-overlay {
              position: absolute;
              top: 0;
              left: 0;
              width: 100%;
              height: 100%;
              background-color: rgba(0, 0, 0, 0.5);
              display: flex;
              justify-content: center;
              align-items: center;
            }
            
            .payment-modal {
              position: relative;
              background-color: transparent;
              border-radius: 12px;
              padding: 0;
              overflow: visible;
              box-shadow: none;
            }
            
            .close-button {
              position: absolute;
              top: -15px;
              right: -15px;
              background-color: #333;
              color: white;
              border: none;
              border-radius: 50%;
              width: 30px;
              height: 30px;
              font-size: 18px;
              cursor: pointer;
              display: flex;
              align-items: center;
              justify-content: center;
              z-index: 10;
              padding: 0;
              line-height: 1;
              box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
            }
            
            .teller-iframe {
              width: 350px;
              height: 600px;
              border: none;
              border-radius: 8px;
              overflow: hidden;
              box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
            }
          `}</style>
        </div>
      );
    };

    export default PhoenixPayment;
    ```
  </Accordion>
</AccordionGroup>

<div style={{ marginTop: '24px', marginBottom: '24px' }}>
  <CardGroup>
    <a href="https://app-partner.phoenix.market/download-phoenix.html" download style={{ textDecoration: 'none', minWidth: '400px', display: 'block' }} target="_blank" rel="noopener noreferrer">
      <Card title="Download Component" icon="download">
        Click to download PhoenixPayment.tsx
      </Card>
    </a>
  </CardGroup>
</div>

Save this file to your project's component directory, for example:
`/src/components/PhoenixPayment.tsx`

<Info>
  The component includes all necessary styling internally via the `<style>` tag, so you don't need to add any additional CSS.
</Info>

## Step 3: Implement the Component

Follow these steps to implement the component in your application:

### Step 3.1: Import the Component

```tsx theme={null}
import { PhoenixPayment } from './components/PhoenixPayment';
```

### Step 3.2: Prepare Required and Optional Parameters

Before adding the component, you need to collect the following information:

#### Required Parameters

* `walletAddress`: The Ethereum wallet address where USDC will be sent
* `amount`: The amount in USD to convert to USDC
* `accessToken`: The access token retrieved from your backend
* `onClose`: Function to handle when the user closes the payment modal
* `onComplete`: Callback function to handle payment completion events

#### Optional Parameters

* `onDone`: Callback function to handle when the payment process is complete
* `onOrderCreated`: Optional callback function to handle when an order is created
* `theme`: Optional UI theme, can be set to either 'light' or 'dark'

You should create form inputs in your UI to collect the required information:

<AccordionGroup>
  <Accordion title="View Input Collection Example">
    ```tsx theme={null}
    // Example of collecting user input
    const [walletAddress, setWalletAddress] = useState('');
    const [amount, setAmount] = useState('');
    const [accessToken, setAccessToken] = useState('');

    useEffect(() => {
      // Fetch the access token from your backend
      fetch('/api/token')
        .then(response => response.json())
        .then(data => setAccessToken(data.access_token))
        .catch(error => console.error('Error fetching access token:', error));
    }, []);
    ```
  </Accordion>
</AccordionGroup>

### Step 3.3: Add the Component to Your JSX

Once you have collected these values, you can pass them to the PhoenixPayment component:

```tsx theme={null}
<PhoenixPayment 
  walletAddress={walletAddress}
  amount={amount}
  accessToken={accessToken}
  onClose={() => setShowPayment(false)}
  onComplete={handlePaymentComplete}
  onDone={handlePaymentDone}
  onOrderCreated={handleOrderCreated} // Optional: handle order creation to receive order details
  theme="dark" // Optional: specify 'light' or 'dark' theme
/>
```

### Step 3.4: Handle Order Created Events

The `onOrderCreated` callback is triggered when a new order is created in the Phoenix system. This happens before the payment process begins. The callback receives an object containing:

* `order_id`: Unique identifier for the order
* `data`: Object containing additional order details:
  * `created_at`: Timestamp of order creation
  * `buyer_address`: The buyer's wallet address
  * `seller_address`: The seller's wallet address
  * `send_amount`: The amount to be sent
  * `receive_amount`: The amount to be received
  * `uniqueness_amount`: The amount of cents added to the order for uniqueness
  * `receiving_chain_id`: The chain ID where the payment will be received
  * `zelle_address`: The Zelle address for payment

```tsx theme={null}
const handleOrderCreated = ({ order_id, data }) => {
  console.log('Order created:', { order_id, data });
  // You can store the order details for reference
};
```

### Step 3.5: Handle Payment Completion

The `onComplete` callback receives three parameters:

1. `success`: Boolean indicating if the operation succeeded
2. `transactionId`: Transaction hash (only for successful payments)
3. `data`: Object containing additional information

#### Transaction Success Data

When a transaction is successful, the data object will contain:

* `amount`: The USD amount
* `token`: The token received (e.g., "USDC")
* `chain`: The blockchain (e.g., "Base")
* `walletAddress`: The receiving wallet address
* `sendAmount`: The amount of tokens sent
* `transactionHash`: The blockchain transaction hash
* `basescanLink`: Link to view the transaction on Basescan

```tsx theme={null}
const handlePaymentComplete = (success, transactionId, data) => {
  if (success) {
    // For transaction success
    if (data?.transactionHash) {
      console.log('Transaction successful:', data);
      
      // You might want to redirect to a success page or show transaction details
      
      // Uncomment the following line if you want to close the window after transaction success
      // setShowPayment(false);
    }
  } else {
    console.log('Payment failed or cancelled');
    
    // Uncomment the following line if you want to close the window after payment failure/cancellation
    // setShowPayment(false);
  }
};
```

### Step 3.6: Handle Done Events

```tsx theme={null}
const handlePaymentDone = () => {
  // Close the payment window
  setShowPayment(false);
};
```

## Full Implementation Example

<AccordionGroup>
  <Accordion title="View Complete Example">
    Here's a complete example showing how all the pieces fit together:

    ```tsx theme={null}
    import { useState, useEffect } from 'react';
    import { PhoenixPayment } from './components/PhoenixPayment';

    function PaymentPage() {
      const [walletAddress, setWalletAddress] = useState('');
      const [amount, setAmount] = useState('');
      const [showPayment, setShowPayment] = useState(false);
      const [accessToken, setAccessToken] = useState('');
      
      useEffect(() => {
        // Fetch the access token from your backend
        fetch('/api/token')
          .then(response => response.json())
          .then(data => setAccessToken(data.access_token))
          .catch(error => console.error('Error fetching access token:', error));
      }, []);
      
      const handlePaymentComplete = (success, transactionId, data) => {
        if (success) {
          // For transaction success
          if (data?.transactionHash) {
            console.log('Transaction successful:', data);
            
            // You might want to redirect to a success page or show transaction details
            
            // Uncomment the following line if you want to close the window after transaction success
            // setShowPayment(false);
          }
        } else {
          console.log('Payment failed or cancelled');
          
          // Uncomment the following line if you want to close the window after payment failure/cancellation
          // setShowPayment(false);
        }
      };
      
      const handlePaymentDone = () => {
        // Close the payment window
        setShowPayment(false);
      };
      
      const handleOrderCreated = ({ order_id, data }) => {
        console.log('Order created:', { order_id, data });
        // You can store the order details for reference
      };
      
      return (
        <>
          {/* Form to collect wallet address and amount */}
          <div>
            <label htmlFor="wallet">Wallet Address:</label>
            <input
              id="wallet"
              type="text"
              value={walletAddress}
              onChange={(e) => setWalletAddress(e.target.value)}
              placeholder="0x..."
            />
          </div>
          <div>
            <label htmlFor="amount">Amount (USD):</label>
            <input
              id="amount"
              type="number"
              value={amount}
              onChange={(e) => setAmount(e.target.value)}
              placeholder="100"
            />
          </div>
          
          <button 
            onClick={() => setShowPayment(true)} 
            disabled={!accessToken} // Disable if access token isn't loaded
          >
            Make Payment
          </button>
          
          {showPayment && accessToken && (
            <PhoenixPayment 
              walletAddress={walletAddress}
              amount={amount}
              accessToken={accessToken}
              onClose={() => setShowPayment(false)}
              onComplete={handlePaymentComplete}
              onDone={handlePaymentDone}
              onOrderCreated={handleOrderCreated}
              theme="dark" // Optional: specify 'light' or 'dark' theme
            />
          )}
        </>
      );
    }
    ```
  </Accordion>
</AccordionGroup>
