# Expo Pngme SDK

A native Expo module for integrating Pngme's financial insights SDK into your Expo managed workflow apps. This SDK enables credit scoring and financial analysis through SMS data collection on Android devices.

## 🎯 Designed for Expo Managed Workflow

This SDK is specifically optimized for **Expo Managed Workflow** projects. No ejecting required!

## 📱 Platform Support

| Platform | Support |
|----------|---------|
| Android | ✅ Full Support |
| iOS | ❌ Not Supported |
| Web | ⚠️ Development Stub |

## 🚀 Installation

### Step 1: Install the Package

```bash
npm install expo-pngme-sdk
# or
yarn add expo-pngme-sdk
# or
expo install expo-pngme-sdk
```

### Step 2: Add to App Config

In your `app.json` or `app.config.js`, add the plugin:

```json
{
  "expo": {
    "plugins": [
      "expo-pngme-sdk"
    ]
  }
}
```

Or with custom configuration:

```json
{
  "expo": {
    "plugins": [
      [
        "expo-pngme-sdk",
        {
          "pngmeSdkVersion": "7.0.6",
          "pngmeMavenUrl": "https://jitpack.io"
        }
      ]
    ]
  }
}
```

### Step 3: Create a Development Build

**⚠️ Important**: This SDK does NOT work with Expo Go due to native module requirements.

```bash
# Using EAS Build (recommended)
eas build --profile development --platform android

# Or using local build
expo run:android

## 💻 Usage

### Basic Implementation

```typescript
import PngmeSDK from 'expo-pngme-sdk';

const initializePngme = async () => {
  try {
    await PngmeSDK.go({
      clientKey: 'YOUR_PNGME_CLIENT_KEY',  // Required
      externalId: 'user_123',               // Required: Your user ID
      companyName: 'Your Company',          // Required
      firstName: 'John',                     // Optional
      lastName: 'Doe',                       // Optional
      email: 'john@example.com',            // Optional
      phoneNumber: '254712345678',         // Optional
    });
    
    console.log('Pngme SDK initialized successfully');
  } catch (error) {
    console.error('Failed to initialize:', error);
  }
};
```

### Custom Dialog Styling

```typescript
await PngmeSDK.go({
  clientKey: 'YOUR_CLIENT_KEY',
  externalId: 'user_123',
  companyName: 'Your Company',
  dialogStyle: {
    // Colors
    primaryColor: '#007AFF',
    backgroundColor: '#FFFFFF',
    buttonBackgroundColor: '#007AFF',
    buttonTextColor: '#FFFFFF',
    
    // Text
    customTitle: 'Enable Financial Insights',
    customButtonText: 'Get Started',
    
    // Sizing
    titleTextSize: 24,
    bodyTextSize: 16,
    buttonCornerRadius: 8,
    
    // URLs
    privacyPolicyUrl: 'https://yourcompany.com/privacy',
    eulaUrl: 'https://yourcompany.com/terms',
  }
});
```

### Event Handling

```typescript
import { useEffect } from 'react';
import PngmeSDK from 'expo-pngme-sdk';

export default function App() {
  useEffect(() => {
    const subscriptions = [
      PngmeSDK.addListener('onPermissionGranted', (event) => {
        console.log('Permission granted:', event.status);
      }),
      
      PngmeSDK.addListener('onSignInComplete', (event) => {
        console.log('User ID:', event.userId);
      }),
      
      PngmeSDK.addListener('onError', (event) => {
        console.error('Error:', event.error);
      }),
    ];
    
    return () => {
      subscriptions.forEach(sub => sub.remove());
    };
  }, []);
  
  // ... rest of your app
}
```

### Check Permission Status

```typescript
const checkStatus = async () => {
  const isGranted = await PngmeSDK.isPermissionGranted();
  
  const status = await PngmeSDK.getPermissionStatus();
  console.log('SMS Permission:', status.smsPermission);
  console.log('Terms Accepted:', status.termsAccepted);
};
```

## 📖 API Reference

### Methods

| Method | Description | Returns |
|--------|-------------|---------|
| `go(config)` | Initialize SDK and show dialog | `Promise<void>` |
| `isPermissionGranted()` | Check if permissions granted | `Promise<boolean>` |
| `getUserUuid()` | Get Pngme user ID | `Promise<string \| null>` |
| `setDefaultStyle(style)` | Set default dialog style | `Promise<void>` |
| `clearDefaultStyle()` | Clear default style | `Promise<void>` |
| `getPermissionStatus()` | Get detailed permission status | `Promise<PngmePermissionStatus>` |

### Events

| Event | Payload | Description |
|-------|---------|-------------|
| `onPermissionGranted` | `{ status }` | Permissions granted |
| `onPermissionDenied` | `{ status }` | Permissions denied |
| `onDialogDismissed` | `{ completed }` | Dialog closed |
| `onSignInComplete` | `{ userId }` | User authenticated |
| `onSmsUploadStarted` | `{ timestamp }` | SMS sync started |
| `onSmsUploadComplete` | `{ success, count? }` | SMS sync finished |
| `onError` | `{ error, code }` | Error occurred |

### Types

```typescript
interface PngmeConfig {
  clientKey: string;          // Your Pngme API key
  externalId: string;         // Your internal user ID
  companyName: string;        // Your company name
  firstName?: string;
  lastName?: string;
  email?: string;
  phoneNumber?: string;
  dialogStyle?: PngmeDialogStyle;
}

interface PngmeDialogStyle {
  // Colors (hex strings)
  primaryColor?: string;
  backgroundColor?: string;
  textColor?: string;
  buttonBackgroundColor?: string;
  buttonTextColor?: string;
  linkTextColor?: string;
  
  // Icon colors
  closeIconColor?: string;
  smsIconColor?: string;
  privacyIconColor?: string;
  
  // Text sizes (sp units)
  titleTextSize?: number;
  bodyTextSize?: number;
  buttonTextSize?: number;
  
  // Custom text
  customTitle?: string;
  customSmsDescription?: string;
  customPrivacyDescription?: string;
  customButtonText?: string;
  
  // Button styling
  buttonCornerRadius?: number;
  buttonElevation?: number;
  
  // URLs
  privacyPolicyUrl?: string;
  eulaUrl?: string;
  
  // Layout
  contentPadding?: number;
}

interface PngmePermissionStatus {
  smsPermission: 'granted' | 'denied' | 'never_asked';
  termsAccepted: boolean;
}
```

## 🎨 Complete Example App

```typescript
import React, { useState, useEffect } from 'react';
import {
  StyleSheet,
  Text,
  View,
  Button,
  TextInput,
  ScrollView,
  Alert,
} from 'react-native';
import PngmeSDK from 'expo-pngme-sdk';

export default function App() {
  const [clientKey, setClientKey] = useState('');
  const [userId, setUserId] = useState('');
  const [status, setStatus] = useState<any>(null);

  useEffect(() => {
    checkStatus();
    
    // Set up event listeners
    const listeners = [
      PngmeSDK.addListener('onPermissionGranted', (event) => {
        Alert.alert('Success', 'Permissions granted!');
        setStatus(event.status);
      }),
      
      PngmeSDK.addListener('onSignInComplete', (event) => {
        setUserId(event.userId);
      }),
      
      PngmeSDK.addListener('onError', (event) => {
        Alert.alert('Error', event.error);
      }),
    ];
    
    return () => listeners.forEach(l => l.remove());
  }, []);

  const checkStatus = async () => {
    const status = await PngmeSDK.getPermissionStatus();
    setStatus(status);
  };

  const initialize = async () => {
    if (!clientKey) {
      Alert.alert('Error', 'Please enter your client key');
      return;
    }
    
    try {
      await PngmeSDK.go({
        clientKey,
        externalId: `user_${Date.now()}`,
        companyName: 'Test Company',
        firstName: 'Test',
        lastName: 'User',
        dialogStyle: {
          primaryColor: '#007AFF',
          buttonBackgroundColor: '#007AFF',
        }
      });
    } catch (error: any) {
      Alert.alert('Error', error.message);
    }
  };

  return (
    <ScrollView style={styles.container}>
      <Text style={styles.title}>Pngme SDK Demo</Text>
      
      <View style={styles.card}>
        <Text style={styles.label}>Status</Text>
        <Text>SMS: {status?.smsPermission || 'Unknown'}</Text>
        <Text>Terms: {status?.termsAccepted ? 'Yes' : 'No'}</Text>
        {userId && <Text>User ID: {userId}</Text>}
      </View>
      
      <View style={styles.card}>
        <Text style={styles.label}>Client Key</Text>
        <TextInput
          style={styles.input}
          value={clientKey}
          onChangeText={setClientKey}
          placeholder="Enter your Pngme client key"
        />
        <Button title="Initialize SDK" onPress={initialize} />
      </View>
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    textAlign: 'center',
    marginVertical: 20,
  },
  card: {
    backgroundColor: 'white',
    padding: 15,
    borderRadius: 10,
    marginBottom: 15,
  },
  label: {
    fontSize: 16,
    fontWeight: '600',
    marginBottom: 10,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 5,
    padding: 10,
    marginBottom: 10,
  },
});
```

## 🔧 Troubleshooting

### Common Issues and Solutions

#### "Module not found" Error
```bash
# Clear cache and rebuild
expo start -c
eas build --clear-cache --platform android
```

#### Permission Dialog Not Showing
- Ensure you're testing on a real Android device or emulator
- Check that `clientKey` and `externalId` are provided
- Verify the app is in the foreground

#### SDK Not Initializing
- Confirm you've created a development build (not using Expo Go)
- Check that the Pngme SDK dependency is correctly configured
- Verify your client key is valid

#### iOS Platform Error
This SDK is **Android-only**. It will not work on iOS devices and will throw appropriate errors.

## 🏗️ Build Configuration

### EAS Build

In your `eas.json`:

```json
{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "android": {
        "buildType": "apk"
      }
    },
    "preview": {
      "distribution": "internal"
    },
    "production": {}
  }
}
```

### Local Build

```bash
# Install dependencies
npm install

# Run on Android
expo run:android

# Build APK locally
expo build:android -t apk
```

## 📊 Data Collection

The SDK collects and processes:
- SMS messages (filtered for financial transactions)
- Basic device information
- User-provided information

All data is:
- Encrypted in transit
- Processed according to privacy regulations
- Used solely for credit scoring purposes

## 🔒 Security Best Practices

1. **Store Client Key Securely**
   ```typescript
   // Use environment variables
   import Constants from 'expo-constants';
   
   const CLIENT_KEY = Constants.expoConfig?.extra?.pngmeClientKey;
   ```

2. **Validate User Data**
   ```typescript
   // Validate before passing to SDK
   const isValidEmail = (email: string) => /\S+@\S+\.\S+/.test(email);
   const isValidPhone = (phone: string) => /^\+\d{10,15}$/.test(phone);
   ```

3. **Handle Errors Gracefully**
   ```typescript
   try {
     await PngmeSDK.go(config);
   } catch (error) {
     // Log to analytics, not console
     analytics.track('pngme_init_failed', { error });
   }
   ```

**Note:** This SDK requires a valid Pngme client key. Contact [Pngme](https://pngme.com) to get started.