npm package: @idto/digilocker-react-native-sdk
Description: Official React Native SDK for integrating DigiLocker authentication with IDTO platform
Author: IDTO
Latest version: 0.1.1

# @idto/digilocker-react-native-sdk

Official React Native SDK for integrating DigiLocker authentication with IDTO platform. Provides secure Aadhaar verification with real-time event tracking and reference key delivery for iOS and Android applications.

## Features

- 🔐 **Secure DigiLocker Integration** - Government-approved Aadhaar verification
- 📱 **Native Mobile Experience** - Optimized bottom sheet for mobile devices
- 🌐 **Multi-language Support** - English & Hindi
- 🔊 **Audio Controls** - User-friendly audio management
- 📡 **Real-time Events** - Track user state and progress
- 🎯 **User State Tracking** - Monitor authentication flow
- 🔑 **Reference Key Delivery** - Get verification results instantly
- 🎨 **Customizable Design** - Custom logos and design tokens
- ⚡ **Lightweight** - Minimal bundle size with maximum functionality
- 📝 **Full TypeScript Support** - Complete type definitions and IntelliSense
- 🎭 **Dark Mode Disabled** - Consistent light theme across all devices

## Installation

```bash
npm install @idto/digilocker-react-native-sdk
# or
yarn add @idto/digilocker-react-native-sdk
# or
pnpm add @idto/digilocker-react-native-sdk
```

### Peer Dependencies

The SDK requires the following peer dependencies:

```bash
npm install react react-native jotai react-native-webview react-native-svg react-native-fast-image
# or
yarn add react react-native jotai react-native-webview react-native-svg react-native-fast-image
```

### iOS Setup

For iOS, you need to install pods:

```bash
cd ios && pod install && cd ..
```

### Android Setup

For Android, ensure your `android/app/build.gradle` has the following configuration:

```gradle
android {
    compileSdkVersion 34
    
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 34
    }
}
```

If you're using Expo, add the following to your `app.json`:

```json
{
  "expo": {
    "plugins": [
      "expo-build-properties"
    ],
    "android": {
      "buildFeatures": {
        "dataBinding": true
      }
    }
  }
}
```

## Quick Start

### Basic Usage

```tsx
import React from 'react';
import { DigilockerSdk } from '@idto/digilocker-react-native-sdk';

function App() {
  return (
    <DigilockerSdk
      userId="user123"
      token="your-auth-token"
    />
  );
}
```

### With Event Handlers

```tsx
import React, { useState } from 'react';
import { DigilockerSdk } from '@idto/digilocker-react-native-sdk';

function App() {
  const [referenceKey, setReferenceKey] = useState('');

  const handleReferenceReceived = (data) => {
    console.log('✅ Reference Key:', data.reference_key);
    setReferenceKey(data.reference_key);
    
    // Send to your backend
    fetch('/api/store-reference', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        userId: data.user_id,
        referenceKey: data.reference_key,
        expiresAt: data.expires_at
      })
    });
  };

  return (
    <DigilockerSdk
      userId="user123"
      token="your-auth-token"
      onReferenceReceived={handleReferenceReceived}
      onError={(data) => console.error('Error:', data.error)}
    />
  );
}
```

### With Bottom Sheet (Mobile)

The SDK automatically opens in a bottom sheet on mobile devices. You can customize the height:

```tsx
import React, { useState } from 'react';
import { DigilockerSdk } from '@idto/digilocker-react-native-sdk';

function App() {
  const [isSdkOpen, setIsSdkOpen] = useState(false);

  return (
    <>
      <Button title="Start Verification" onPress={() => setIsSdkOpen(true)} />
      
      {isSdkOpen && (
        <DigilockerSdk
          userId="user123"
          token="your-auth-token"
          bottomSheetHeight={0.75} // 75% of screen height
          autoOpen={true} // Opens directly to verification flow
          onSessionCompleted={() => setIsSdkOpen(false)}
        />
      )}
    </>
  );
}
```

## Event-Driven Architecture

The SDK emits real-time events to keep your application informed about the user's DigiLocker authentication status.

### Event Types

| Event | Description | Data Payload |
|-------|-------------|--------------|
| `SESSION_INITIATED` | DigiLocker session started | `{ user_id, redirect_url }` |
| `REFERENCE_RECEIVED` | **Reference key received** | `{ user_id, reference_key, expires_at }` |
| `SESSION_COMPLETED` | Authentication completed | `{ user_id }` |
| `ERROR_OCCURRED` | Error during process | `{ user_id, error, error_code }` |
| `SESSION_EXPIRED` | Session expired | `{ user_id, reference_key }` |
| `LANGUAGE_CHANGED` | Language preference changed | `{ language, language_code }` |
| `AUDIO_TOGGLED` | Audio state changed | `{ is_muted }` |

### Using Event Callbacks

```tsx
import { DigilockerSdk } from '@idto/digilocker-react-native-sdk';

function App() {
  const handleReferenceReceived = (data) => {
    console.log('✅ Reference Key:', data.reference_key);
    console.log('⏰ Expires at:', data.expires_at);
    
    // Store reference key in your database
    saveReferenceKey(data.user_id, data.reference_key);
  };

  const handleSessionCompleted = (data) => {
    console.log('🎉 Session completed for user:', data.user_id);
    // Update UI or navigate
  };

  const handleError = (data) => {
    console.error('❌ Error occurred:', data.error);
    // Show error message to user
    Alert.alert('Error', data.error);
  };

  return (
    <DigilockerSdk
      userId="user123"
      token="your-auth-token"
      onReferenceReceived={handleReferenceReceived}
      onSessionCompleted={handleSessionCompleted}
      onError={handleError}
    />
  );
}
```

### Global Event Emitter

For advanced event handling across components:

```tsx
import { globalEventEmitter } from '@idto/digilocker-react-native-sdk';

// Listen to all events
globalEventEmitter.on('REFERENCE_RECEIVED', (event) => {
  console.log('Event:', event.type);
  console.log('Data:', event.data);
  console.log('Timestamp:', event.timestamp);
});

// Listen to specific events
globalEventEmitter.on('SESSION_INITIATED', (event) => {
  console.log('Session initiated for user:', event.data.user_id);
});

// Remove listener
const handleError = (event) => console.log('Error:', event.data.error);
globalEventEmitter.on('ERROR_OCCURRED', handleError);

// Later remove the listener
globalEventEmitter.off('ERROR_OCCURRED', handleError);

// Remove all listeners
globalEventEmitter.removeAllListeners();
```

### React Hooks

Use the provided React hooks for component-level event handling:

```tsx
import { useEventListener } from '@idto/digilocker-react-native-sdk';

function MyComponent() {
  useEventListener('REFERENCE_RECEIVED', (event) => {
    console.log('Reference received:', event.data.reference_key);
  });

  useEventListener('ERROR_OCCURRED', (event) => {
    console.error('Error:', event.data.error);
  });

  return <View>Listening to events...</View>;
}
```

## Customization

### Custom Logos

You can customize the logos used in the SDK:

```tsx
import { DigilockerSdk } from '@idto/digilocker-react-native-sdk';
import { Image } from 'react-native';

function App() {
  return (
    <DigilockerSdk
      userId="user123"
      token="your-auth-token"
      logo={{
        headerLogo: <Image source={require('./assets/logo.png')} />,
        brandingLogo: 'https://example.com/branding-logo.png',
        digilockerLogo: <CustomDigilockerIcon />
      }}
    />
  );
}
```

**Logo Types:**
- `headerLogo`: Logo displayed in the header (React component or image URL)
- `brandingLogo`: Logo displayed in the branding section (React component or image URL)
- `digilockerLogo`: DigiLocker icon (React component or image URL)

### Custom Design Tokens

Customize colors, typography, spacing, and border radius:

```tsx
import { DigilockerSdk } from '@idto/digilocker-react-native-sdk';

function App() {
  return (
    <DigilockerSdk
      userId="user123"
      token="your-auth-token"
      designTokens={{
        colors: {
          primaryBlue: '#0066FF',
          primaryBlueHover: '#0052CC',
          successGreen: '#00C853',
          errorRed: '#FF1744',
        },
        typography: {
          fontFamily: 'System',
          fontSize: {
            base: 16,
            lg: 18,
            xl: 20,
          },
        },
        spacing: {
          padding: {
            md: 16,
            lg: 24,
          },
        },
        borderRadius: {
          md: 8,
          lg: 12,
        },
      }}
    />
  );
}
```

### Bottom Sheet Height

Control the height of the bottom sheet on mobile:

```tsx
<DigilockerSdk
  userId="user123"
  token="your-auth-token"
  bottomSheetHeight={0.75} // 75% of screen height (0-1)
  // or
  bottomSheetHeight={600} // Fixed height in pixels
/>
```

### Auto Open

Skip the landing page and open directly to the verification flow:

```tsx
<DigilockerSdk
  userId="user123"
  token="your-auth-token"
  autoOpen={true} // Opens directly to verification, skipping landing page
/>
```

## Complete Integration Example

```tsx
import React, { useState } from 'react';
import { View, Button, Text, Alert } from 'react-native';
import { DigilockerSdk } from '@idto/digilocker-react-native-sdk';

function App() {
  const [isSdkOpen, setIsSdkOpen] = useState(false);
  const [referenceKey, setReferenceKey] = useState('');
  const [sessionStatus, setSessionStatus] = useState('idle');

  const handleReferenceReceived = (data) => {
    setReferenceKey(data.reference_key);
    setSessionStatus('completed');
    
    // Send to your backend
    fetch('/api/store-reference', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        userId: data.user_id,
        referenceKey: data.reference_key,
        expiresAt: data.expires_at
      })
    });
  };

  const handleSessionInitiated = (data) => {
    setSessionStatus('initiated');
    console.log('Redirecting to:', data.redirect_url);
  };

  const handleError = (data) => {
    setSessionStatus('error');
    Alert.alert('Error', data.error);
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
      <Button
        title="Start Aadhaar Verification"
        onPress={() => setIsSdkOpen(true)}
      />
      
      {sessionStatus === 'completed' && (
        <View style={{ marginTop: 20 }}>
          <Text>✅ Verification Complete!</Text>
          <Text>Reference Key: {referenceKey}</Text>
        </View>
      )}

      {isSdkOpen && (
        <DigilockerSdk
          userId="user123"
          token="your-auth-token"
          bottomSheetHeight={0.75}
          autoOpen={true}
          onReferenceReceived={handleReferenceReceived}
          onSessionInitiated={handleSessionInitiated}
          onError={handleError}
          onSessionCompleted={() => {
            setIsSdkOpen(false);
            setSessionStatus('completed');
          }}
        />
      )}
    </View>
  );
}

export default App;
```

## API Reference

### Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `userId` | string | ✅ | - | Unique identifier for the user |
| `token` | string | ✅ | - | Authentication token |
| `isShowDrawerInMobile` | boolean | ❌ | false | Show drawer on mobile devices |
| `logo` | LogoConfig | ❌ | - | Custom logos configuration |
| `designTokens` | DesignTokens | ❌ | - | Custom design tokens |
| `bottomSheetHeight` | number | ❌ | 0.75 | Bottom sheet height (0-1 for percentage, or pixel value) |
| `autoOpen` | boolean | ❌ | false | Open directly to verification flow |

### Event Callback Props

| Prop | Type | Description |
|------|------|-------------|
| `onSessionInitiated` | function | Called when session is initiated |
| `onReferenceReceived` | function | Called when reference key is received |
| `onSessionCompleted` | function | Called when session is completed |
| `onError` | function | Called when an error occurs |
| `onSessionExpired` | function | Called when session expires |
| `onLanguageChanged` | function | Called when language is changed |
| `onAudioToggled` | function | Called when audio is toggled |

### Event Data Structure

```typescript
interface DigilockerEvent {
  type: DigilockerEventType;
  timestamp: number;
  data?: any;
}
```

### TypeScript Support

This package includes complete TypeScript declarations. No additional `@types` packages are required.

```typescript
import { DigilockerSdk, DigilockerEvent, DigilockerSdkProps } from '@idto/digilocker-react-native-sdk';

// Full IntelliSense support
const handleEvent = (event: DigilockerEvent) => {
  console.log(event.type, event.data);
};

const props: DigilockerSdkProps = {
  userId: 'user123',
  token: 'your-token',
  onReferenceReceived: (data) => {
    console.log(data.reference_key);
  }
};
```

## Platform-Specific Notes

### iOS

- The SDK uses native iOS WebView for DigiLocker authentication
- Bottom sheet animations use native iOS spring animations
- Dark mode is explicitly disabled to maintain consistent UI

### Android

- The SDK uses native Android WebView for DigiLocker authentication
- Bottom sheet supports drag-to-close gesture
- Dark mode is explicitly disabled to maintain consistent UI

### Responsive Behavior

- **Mobile**: Opens in a bottom sheet with configurable height
- The SDK automatically detects screen size and adjusts the UI accordingly

## Error Handling

Comprehensive error handling with specific error codes:

```tsx
const handleError = (data) => {
  switch (data.error_code) {
    case 'SESSION_INITIATION_FAILED':
      Alert.alert('Error', 'Failed to start verification. Please try again.');
      break;
    case 'REFERENCE_FETCH_FAILED':
      Alert.alert('Error', 'Verification failed. Please restart the process.');
      break;
    default:
      Alert.alert('Error', data.error || 'An unexpected error occurred.');
      break;
  }
};
```

## Requirements

- React >= 16.8.0
- React Native >= 0.70.0
- Jotai >= 2.0.0
- react-native-webview >= 13.0.0
- react-native-svg >= 15.0.0
- react-native-fast-image >= 8.0.0
- Node.js >= 14.0.0

## Troubleshooting

### Bottom Sheet Not Appearing

If the bottom sheet doesn't appear:

1. **Check `autoOpen` prop**: Set `autoOpen={true}` to skip the landing page
2. **Check `bottomSheetHeight`**: Ensure it's between 0 and 1 (for percentage) or a positive number (for pixels)
3. **Check device type**: The SDK automatically detects mobile devices and renders accordingly

### WebView Not Loading

If the WebView doesn't load:

1. **Check network permissions**: Ensure your app has internet permissions
2. **Check token validity**: Verify your authentication token is valid
3. **Check userId**: Ensure the userId is correct and valid

### TypeScript Errors

If you encounter TypeScript errors:

1. **Check peer dependencies**: Ensure all peer dependencies are installed
2. **Check TypeScript version**: Ensure you're using TypeScript >= 4.5.0
3. **Clear cache**: Try clearing your TypeScript cache and rebuilding

## Development

### Build the Package

```bash
npm run prepare
# or
yarn prepare
# or
pnpm prepare
```

This creates the distribution files in the `lib/` folder, including:
- **ESM Bundle**: `lib/module/index.js` - For modern bundlers
- **TypeScript Declarations**: `lib/typescript/src/index.d.ts` - For full type support

### Type Checking

```bash
npm run typecheck
```

### Linting

```bash
npm run lint
```

### Running the Example App

```bash
cd example
npm install
npm start
# or
yarn install
yarn start
```

Then press `i` for iOS or `a` for Android.

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Support

- 📧 Email: support@idto.ai
- 📖 Documentation: [https://docs.idto.ai](https://docs.idto.ai)

---

Built with ❤️ by [IDTO](https://idto.ai)