npm package: @paygate/expo
Description: PayGate Expo SDK - Accept Mobile Money payments in Ghana (WebView + expo-web-browser)
Author: Ebenezer Sakyi
Latest version: 0.1.0

# @paygate/expo

Official PayGate Expo SDK for accepting Mobile Money payments in Ghana.

## Features

- **WebView Mode**: Embedded checkout in a modal (default)
- **Browser Mode**: Open checkout in system browser (optional, using expo-web-browser)
- **Deep Linking**: Return to app after browser checkout

## Installation

```bash
npx expo install @paygate/expo react-native-webview

# Optional: For browser mode
npx expo install expo-web-browser expo-linking
```

## Quick Start

### 1. Wrap your app with PayGateProvider

```tsx
import { PayGateProvider, PayGateAutoModal } from '@paygate/expo';

export default function App() {
  return (
    <PayGateProvider
      publicKey="pk_test_your_public_key"
      baseUrl="https://paygate.com"
      urlScheme="myapp" // For browser mode deep linking
    >
      <NavigationContainer>
        <AppNavigator />
      </NavigationContainer>
      <PayGateAutoModal />
    </PayGateProvider>
  );
}
```

### 2. Configure deep linking (for browser mode)

In your `app.json`:

```json
{
  "expo": {
    "scheme": "myapp"
  }
}
```

### 3. Create a checkout session on your server

```typescript
// Server-side
import PayGate from 'paygate';

const paygate = new PayGate('sk_test_your_secret_key');

const session = await paygate.checkoutSessions.create({
  amount: 100.00,
  currency: 'GHS',
  success_url: 'https://yoursite.com/success',
  cancel_url: 'https://yoursite.com/cancel',
});

// Return session.id to your app
```

### 4. Trigger payments

```tsx
import { usePayGate } from '@paygate/expo';
import { Button, Alert, View } from 'react-native';

function CheckoutScreen() {
  const { checkout, openCheckoutInBrowser, browserAvailable, isVisible } = usePayGate();

  const handlePayWithWebView = async () => {
    const { sessionId } = await api.createCheckoutSession();

    checkout({
      sessionId,
      onSuccess: (data) => {
        console.log('Payment successful!', data);
        Alert.alert('Success', 'Payment completed!');
      },
      onCancel: () => {
        console.log('Payment cancelled');
      },
      onError: (error) => {
        Alert.alert('Error', error.message);
      },
    });
  };

  const handlePayWithBrowser = async () => {
    const { sessionId } = await api.createCheckoutSession();

    await openCheckoutInBrowser({
      sessionId,
      onSuccess: (data) => {
        Alert.alert('Success', 'Payment completed!');
      },
      onCancel: () => {
        console.log('Cancelled');
      },
    });
  };

  return (
    <View>
      <Button
        title="Pay with WebView"
        onPress={handlePayWithWebView}
        disabled={isVisible}
      />
      {browserAvailable && (
        <Button
          title="Pay with Browser"
          onPress={handlePayWithBrowser}
        />
      )}
    </View>
  );
}
```

## Components

### PayGateProvider

```tsx
<PayGateProvider
  publicKey="pk_test_xxx"      // Required
  baseUrl="https://paygate.com" // Optional
  urlScheme="myapp"             // Required for browser mode
  defaultMode="webview"         // 'webview' | 'browser'
>
  {children}
</PayGateProvider>
```

### PayGateAutoModal

Auto-managed modal that responds to `checkout()` and `payWithLink()` calls.

```tsx
<PayGateAutoModal />
```

### PayGateModal

Manually controlled modal.

```tsx
<PayGateModal
  visible={visible}
  sessionId="cs_xxx"
  onSuccess={(data) => {}}
  onCancel={() => {}}
  onClose={() => setVisible(false)}
/>
```

### PayGate

Low-level WebView component.

```tsx
<PayGate
  sessionId="cs_xxx"
  onSuccess={(data) => {}}
  onCancel={() => {}}
  onError={(error) => {}}
  style={{ flex: 1 }}
/>
```

## Hooks

### usePayGate

```tsx
const {
  // WebView mode
  checkout,                  // (params) => void
  payWithLink,               // (params) => void

  // Browser mode
  openCheckoutInBrowser,     // (params) => Promise<void>
  openPaymentLinkInBrowser,  // (params) => Promise<void>

  // State
  close,                     // () => void
  isVisible,                 // boolean
  mode,                      // 'webview' | 'browser'
  setMode,                   // (mode) => void
  browserAvailable,          // boolean
  publicKey,                 // string
  baseUrl,                   // string
} = usePayGate();
```

## Payment Links

```tsx
const { payWithLink, openPaymentLinkInBrowser } = usePayGate();

// WebView mode
payWithLink({
  linkId: 'pl_xxx',
  amount: 50.00,  // For dynamic amount
  email: 'customer@example.com',
  onSuccess: (data) => console.log('Paid!', data),
});

// Browser mode
await openPaymentLinkInBrowser({
  linkId: 'pl_xxx',
  amount: 50.00,
  onSuccess: (data) => console.log('Paid!', data),
});
```

## WebView vs Browser Mode

| Feature | WebView Mode | Browser Mode |
|---------|-------------|--------------|
| User Experience | In-app modal | System browser |
| Setup | Simpler | Requires deep linking |
| Dependencies | react-native-webview | + expo-web-browser, expo-linking |
| Best for | Most apps | Apps needing browser features |

## TypeScript

```typescript
import type {
  PayGateConfig,
  CheckoutParams,
  PaymentLinkParams,
  PaymentResult,
  PayGateError,
  PaymentMode,
} from '@paygate/expo';
```

## Test Mode

Use test keys (`pk_test_xxx`) during development to simulate payments without processing real transactions.

## Troubleshooting

### WebView not loading

```bash
npx expo install react-native-webview
```

### Browser mode not working

1. Install dependencies:
```bash
npx expo install expo-web-browser expo-linking
```

2. Configure URL scheme in `app.json`:
```json
{
  "expo": {
    "scheme": "myapp"
  }
}
```

3. Pass `urlScheme` to provider:
```tsx
<PayGateProvider publicKey="..." urlScheme="myapp">
```

### Deep link not returning to app

Make sure your URL scheme matches in:
- `app.json` → `expo.scheme`
- `PayGateProvider` → `urlScheme` prop

## License

MIT