npm package: @fnel/react
Description: React/Next.js SDK for fnel funnel tracking
Author: fnel
Latest version: 1.0.1

# @fnel/react

React/Next.js SDK for fnel funnel tracking. This package provides a React Provider and hooks for easy integration of fnel tracking into your React applications.

## Features

- 🚀 **Easy Integration**: Simple Provider pattern with React hooks
- 🔄 **Auto-initialization**: Automatically loads and initializes the fnel SDK
- 📱 **React Native Ready**: Works with React Native (web only)
- 🎯 **Funnel Tracking**: Dedicated hooks for funnel step tracking
- 💾 **State Management**: Automatic state synchronization with the SDK
- 🛡️ **TypeScript**: Full TypeScript support with comprehensive types
- 🔧 **Debug Support**: Access to debug information and SDK state

## Installation

```bash
npm install @fnel/react
# or
yarn add @fnel/react
# or
pnpm add @fnel/react
```

## Quick Start

### 1. Wrap your app with FnelProvider

```tsx
import { FnelProvider } from '@fnel/react';

function App() {
  return (
    <FnelProvider apiToken="your-api-token-here">
      <YourApp />
    </FnelProvider>
  );
}
```

### 2. Use the tracking hook

```tsx
import { useFnel } from '@fnel/react';

function LandingPage() {
  const { track, isInitialized } = useFnel();

  useEffect(() => {
    if (isInitialized) {
      track({
        name: 'landing_page',
        step: 1,
        funnel: 'abc123def'
      });
    }
  }, [isInitialized, track]);

  return <div>Welcome to our landing page!</div>;
}
```

## API Reference

### FnelProvider

The main provider component that initializes the fnel SDK.

```tsx
<FnelProvider
  apiToken="your-api-token"
  autoInit={true}
  onInit={(result) => console.log('Initialized:', result)}
  onError={(error) => console.error('Error:', error)}
>
  {children}
</FnelProvider>
```

#### Props

- `apiToken` (required): Your fnel API token
- `autoInit` (optional): Whether to automatically initialize on mount (default: true)
- `onInit` (optional): Callback when initialization succeeds
- `onError` (optional): Callback when errors occur

### useFnel

The main hook that provides access to all fnel functionality.

```tsx
const {
  isInitialized,
  userId,
  track,
  version,
  getUserId,
  getQueueLength,
  clearQueue,
  clearStorage,
  reset
} = useFnel();
```

#### Returns

- `isInitialized`: Boolean indicating if the SDK is ready
- `userId`: Current user ID (string or null)
- `track`: Function to track events
- `version`: SDK version string
- `getUserId()`: Function to get current user ID
- `getQueueLength()`: Function to get number of queued events
- `clearQueue()`: Function to clear the event queue
- `clearStorage()`: Function to clear stored user data
- `reset()`: Function to reset the entire SDK state

### useFunnelTracking

A convenience hook for tracking funnel steps.

```tsx
const { trackStep, trackLandingPage, trackConversion, isInitialized } = useFunnelTracking('funnel123');

// Track a specific step
await trackStep(2, 'signup_form', { source: 'google_ads' });

// Track landing page
await trackLandingPage({ referrer: 'facebook' });

// Track conversion
await trackConversion({ value: 99.99, currency: 'USD' });
```

#### Parameters

- `funnelId`: The short ID of your funnel

#### Returns

- `trackStep(step, name?, data?)`: Track a specific funnel step
- `trackLandingPage(data?)`: Track landing page (step 1)
- `trackConversion(data?)`: Track conversion (step 999)
- `isInitialized`: Boolean indicating if the SDK is ready

## Usage Examples

### Basic Event Tracking

```tsx
import { useFnel } from '@fnel/react';

function CheckoutPage() {
  const { track, isInitialized } = useFnel();

  const handlePurchase = async () => {
    if (isInitialized) {
      try {
        await track({
          name: 'purchase_completed',
          step: 5,
          funnel: 'ecommerce_funnel',
          amount: 99.99,
          currency: 'USD'
        });
        console.log('Purchase tracked successfully!');
      } catch (error) {
        console.error('Failed to track purchase:', error);
      }
    }
  };

  return (
    <button onClick={handlePurchase}>
      Complete Purchase
    </button>
  );
}
```

### Funnel Step Tracking

```tsx
import { useFunnelTracking } from '@fnel/react';

function SignupFlow() {
  const { trackStep, isInitialized } = useFunnelTracking('signup_funnel');

  const handleEmailSubmit = async (email: string) => {
    if (isInitialized) {
      await trackStep(2, 'email_entered', { email });
    }
    // Continue with signup logic
  };

  const handleFormSubmit = async (formData: any) => {
    if (isInitialized) {
      await trackStep(3, 'form_submitted', { fields: Object.keys(formData) });
    }
    // Submit form
  };

  return (
    <div>
      <input 
        type="email" 
        placeholder="Enter email"
        onBlur={(e) => handleEmailSubmit(e.target.value)}
      />
      <button onClick={() => handleFormSubmit({ email: 'test@example.com' })}>
        Sign Up
      </button>
    </div>
  );
}
```

### Advanced Configuration

```tsx
import { FnelProvider } from '@fnel/react';

function App() {
  const handleInit = (result) => {
    console.log('fnel initialized with user:', result.userId);
  };

  const handleError = (error) => {
    console.error('fnel error:', error);
    // Maybe show a user-friendly error message
  };

  return (
    <FnelProvider
      apiToken={process.env.REACT_APP_FNEL_TOKEN}
      autoInit={true}
      onInit={handleInit}
      onError={handleError}
    >
      <YourApp />
    </FnelProvider>
  );
}
```

### Manual Initialization

```tsx
import { FnelProvider } from '@fnel/react';

function App() {
  return (
    <FnelProvider apiToken="your-token" autoInit={false}>
      <ManualInitExample />
    </FnelProvider>
  );
}

function ManualInitExample() {
  const { track, isInitialized } = useFnel();

  const handleManualInit = async () => {
    // You can manually trigger initialization here
    // The SDK will handle this automatically when you first call track()
  };

  const handleTrack = async () => {
    if (!isInitialized) {
      console.log('SDK not ready, event will be queued');
    }
    
    await track({
      name: 'manual_track',
      step: 1,
      funnel: 'test_funnel'
    });
  };

  return (
    <div>
      <button onClick={handleTrack}>
        Track Event
      </button>
      <p>Status: {isInitialized ? 'Ready' : 'Not Ready'}</p>
    </div>
  );
}
```

## Error Handling

The SDK automatically handles common errors and provides callbacks for error handling:

```tsx
<FnelProvider
  apiToken="your-token"
  onError={(error) => {
    if (error.message.includes('Subscription')) {
      // Handle subscription errors
      showUpgradePrompt();
    } else if (error.message.includes('timeout')) {
      // Handle timeout errors
      showRetryMessage();
    } else {
      // Handle other errors
      console.error('Unexpected error:', error);
    }
  }}
>
  {children}
</FnelProvider>
```

## Debug Information

Access debug information for development:

```tsx
import { fnelSDK } from '@fnel/react';

// Get debug info
const debugInfo = fnelSDK.getDebugInfo();
console.log('Debug info:', debugInfo);

// Or access directly from window (if available)
if (window._fnelDebug) {
  console.log('API Token:', window._fnelDebug.apiToken());
  console.log('User ID:', window._fnelDebug.userId());
  console.log('Initialized:', window._fnelDebug.isInitialized());
  console.log('Queue:', window._fnelDebug.queue());
  console.log('Version:', window._fnelDebug.version);
}
```

## TypeScript

The package includes comprehensive TypeScript types:

```tsx
import { FnelEvent, FnelInitResult, FnelTrackResult } from '@fnel/react';

// Define custom event data
interface CustomEventData extends FnelEvent {
  amount?: number;
  currency?: string;
  source?: string;
}

// Use with tracking
const trackCustomEvent = async (data: CustomEventData) => {
  const result: FnelTrackResult = await track(data);
  return result;
};
```

## Browser Support

- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+

## React Native

This package works with React Native (web only) as it depends on browser APIs like `localStorage` and `fetch`.

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Support

For support, email support@fnel.app or join our Slack channel.