@gmisoftware/react-native-pay 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +909 -234
  2. package/package.json +4 -2
package/README.md CHANGED
@@ -1,78 +1,186 @@
1
- # react-native-pay
1
+ # React Native Pay
2
2
 
3
- A unified React Native payment module supporting both Apple Pay (iOS) and Google Pay (Android) with a consistent API across platforms.
3
+ <div align="center">
4
+
5
+ A unified React Native payment module supporting **Apple Pay** (iOS) and **Google Pay** (Android) with a consistent, type-safe API.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@gmisoftware/react-native-pay.svg)](https://www.npmjs.com/package/@gmisoftware/react-native-pay)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
10
+ [![Expo Compatible](https://img.shields.io/badge/Expo-Compatible-000020.svg)](https://expo.dev/)
4
11
 
5
12
  Built with [Nitro Modules](https://nitro.margelo.com/) for high-performance native integration.
6
13
 
14
+ [Features](#features) • [Installation](#installation) • [Quick Start](#quick-start) • [Documentation](#documentation) • [API Reference](#api-reference)
15
+
16
+ </div>
17
+
18
+ ---
19
+
7
20
  ## Features
8
21
 
9
- - ✅ **Unified API** - Same interface for both Apple Pay and Google Pay
10
- - ✅ **One Hook Does Everything** - Simple `usePaymentCheckout()` hook for complete payment flow
11
- - ✅ **Native UI Components** - Platform-specific payment buttons
12
- - ✅ **Type-Safe** - Full TypeScript support with comprehensive type definitions
13
- - ✅ **Configurable** - Dynamic environment and gateway configuration
14
- - ✅ **Built-in Cart** - Shopping cart functionality included
22
+ - ✅ **Unified API** - Single interface for both Apple Pay and Google Pay
23
+ - ✅ **One Hook Does Everything** - Complete payment flow with `usePaymentCheckout()` hook
24
+ - ✅ **Native UI Components** - Platform-specific payment buttons with full customization
25
+ - ✅ **Type-Safe** - Comprehensive TypeScript definitions with full IntelliSense support
26
+ - ✅ **Configurable** - Dynamic environment and gateway configuration for both platforms
27
+ - ✅ **Built-in Cart** - Shopping cart functionality with batch operations
15
28
  - ✅ **Modern Architecture** - Built with Nitro Modules for optimal performance
16
- - ✅ **Expo Compatible** - Config plugins for easy integration with Expo
29
+ - ✅ **Expo Compatible** - Config plugins for seamless Expo integration
30
+ - ✅ **Production Ready** - Used in production apps with millions of transactions
31
+
32
+ ---
17
33
 
18
34
  ## Installation
19
35
 
36
+ ### Step 1: Install React Native Nitro Modules
37
+
38
+ This package requires `react-native-nitro-modules` to work. Install it first:
39
+
40
+ ```bash
41
+ npm install react-native-nitro-modules
42
+ # or
43
+ yarn add react-native-nitro-modules
44
+ # or
45
+ bun add react-native-nitro-modules
46
+ ```
47
+
48
+ ### Step 2: Install React Native Pay
49
+
20
50
  ```bash
21
- npm install react-native-pay
51
+ npm install @gmisoftware/react-native-pay
22
52
  # or
23
- yarn add react-native-pay
53
+ yarn add @gmisoftware/react-native-pay
24
54
  # or
25
- bun add react-native-pay
55
+ bun add @gmisoftware/react-native-pay
56
+ ```
57
+
58
+ ### Prerequisites
59
+
60
+ - React Native 0.70+
61
+ - React Native Nitro Modules 0.31.4+ (required)
62
+ - Expo 53+ (if using Expo)
63
+
64
+ ---
65
+
66
+ ## Platform Setup
67
+
68
+ ### iOS Setup (Apple Pay)
69
+
70
+ #### 1. Configure Expo Config Plugin
71
+
72
+ Add the Apple Pay plugin to your `app.json` or `app.config.js`:
73
+
74
+ ```js
75
+ {
76
+ "expo": {
77
+ "plugins": [
78
+ [
79
+ "@gmisoftware/react-native-pay",
80
+ {
81
+ "merchantIdentifier": "merchant.com.yourcompany.app"
82
+ }
83
+ ]
84
+ ]
85
+ }
86
+ }
87
+ ```
88
+
89
+ #### 2. Apple Developer Account Setup
90
+
91
+ 1. **Create a Merchant ID** in Apple Developer Portal:
92
+ - Go to [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/list/merchant)
93
+ - Create a new Merchant ID (e.g., `merchant.com.yourcompany.app`)
94
+ - Add it to your app's capabilities
95
+
96
+ 2. **Enable Apple Pay** in your App ID:
97
+ - Go to your App ID settings
98
+ - Enable "Apple Pay Payment Processing"
99
+ - Associate your Merchant ID
100
+
101
+ 3. **Create Payment Processing Certificate**:
102
+ - Create a Payment Processing Certificate for your Merchant ID
103
+ - Download and install it in your payment processor (Stripe, etc.)
104
+
105
+ #### 3. Run Prebuild (Expo)
106
+
107
+ ```bash
108
+ npx expo prebuild --clean
26
109
  ```
27
110
 
28
- ### iOS Setup
111
+ ### Android Setup (Google Pay)
29
112
 
30
- Add Apple Pay capability to your app and configure merchant identifiers in your Expo config:
113
+ #### 1. Configure Expo Config Plugin
114
+
115
+ Add the Google Pay plugin to your `app.json` or `app.config.js`:
31
116
 
32
117
  ```js
33
- // app.json or app.config.js
34
118
  {
35
- "plugins": [
36
- [
37
- "react-native-pay",
38
- {
39
- "merchantIdentifier": "merchant.com.yourcompany.app"
40
- }
119
+ "expo": {
120
+ "plugins": [
121
+ [
122
+ "@gmisoftware/react-native-pay",
123
+ {
124
+ "enableGooglePay": true
125
+ }
126
+ ]
41
127
  ]
42
- ]
128
+ }
43
129
  }
44
130
  ```
45
131
 
46
- ### Android Setup
132
+ #### 2. Google Cloud Console Setup
133
+
134
+ 1. **Enable Google Pay API**:
135
+ - Go to [Google Cloud Console](https://console.cloud.google.com/)
136
+ - Enable the Google Pay API for your project
137
+
138
+ 2. **Register Your App** (Production Only):
139
+ - Submit your app for Google Pay approval
140
+ - Provide screenshots and business information
141
+ - Get your production gateway merchant ID from your payment processor
142
+
143
+ #### 3. Run Prebuild (Expo)
144
+
145
+ ```bash
146
+ npx expo prebuild --clean
147
+ ```
148
+
149
+ ### Combined Setup (Both Platforms)
47
150
 
48
- Enable Google Pay in your Expo config:
151
+ For apps supporting both platforms:
49
152
 
50
153
  ```js
51
- // app.json or app.config.js
52
154
  {
53
- "plugins": [
54
- [
55
- "react-native-pay",
56
- {
57
- "enableGooglePay": true
58
- }
155
+ "expo": {
156
+ "plugins": [
157
+ [
158
+ "@gmisoftware/react-native-pay",
159
+ {
160
+ "merchantIdentifier": "merchant.com.yourcompany.app",
161
+ "enableGooglePay": true
162
+ }
163
+ ]
59
164
  ]
60
- ]
165
+ }
61
166
  }
62
167
  ```
63
168
 
64
- ## Usage
169
+ ---
170
+
171
+ ## Quick Start
65
172
 
66
- ### Using the Hook (Recommended)
173
+ ### Basic Example with Hook (Recommended)
67
174
 
68
- One hook does everything - availability checking, cart management, and payment processing:
175
+ The easiest way to integrate payments - one hook handles everything:
69
176
 
70
177
  ```typescript
178
+ import React from 'react'
71
179
  import {
72
180
  usePaymentCheckout,
73
181
  ApplePayButton,
74
182
  GooglePayButton,
75
- } from 'react-native-pay'
183
+ } from '@gmisoftware/react-native-pay'
76
184
  import { Platform, View, Text, Button, ActivityIndicator } from 'react-native'
77
185
 
78
186
  function CheckoutScreen() {
@@ -97,226 +205,202 @@ function CheckoutScreen() {
97
205
  countryCode: 'US',
98
206
  })
99
207
 
100
- // Add single item
101
- const handleAddCoffee = () => addItem('Coffee', 4.99)
208
+ const handleAddCoffee = () => {
209
+ addItem('Coffee', 4.99)
210
+ }
102
211
 
103
- // Add multiple items at once
104
- const handleAddFullOrder = () => addItems([
105
- { label: 'Coffee', amount: 4.99 },
106
- { label: 'Sandwich', amount: 8.99 },
107
- { label: 'Tax', amount: 1.20 }
108
- ])
212
+ const handleAddFullOrder = () => {
213
+ addItems([
214
+ { label: 'Coffee', amount: 4.99 },
215
+ { label: 'Sandwich', amount: 8.99 },
216
+ { label: 'Tax', amount: 1.20, type: 'final' }
217
+ ])
218
+ }
109
219
 
110
220
  const handlePay = async () => {
111
221
  const result = await startPayment()
112
- if (result?.success) {
113
- // Send result.token to your server
222
+
223
+ if (result?.success && result.token) {
224
+ // Send result.token to your server for processing
114
225
  console.log('Payment successful:', result.transactionId)
226
+ console.log('Token:', result.token)
227
+
228
+ // Call your backend
229
+ await fetch('https://api.yourserver.com/process-payment', {
230
+ method: 'POST',
231
+ headers: { 'Content-Type': 'application/json' },
232
+ body: JSON.stringify({
233
+ token: result.token,
234
+ transactionId: result.transactionId,
235
+ }),
236
+ })
115
237
  }
116
238
  }
117
239
 
118
240
  if (!canMakePayments) {
119
- return <Text>Payment not available</Text>
241
+ return (
242
+ <View>
243
+ <Text>Apple Pay or Google Pay is not available on this device</Text>
244
+ </View>
245
+ )
120
246
  }
121
247
 
122
248
  return (
123
- <View>
124
- <Button title="Add Coffee $4.99" onPress={handleAddCoffee} />
249
+ <View style={{ padding: 20 }}>
250
+ <Button title="Add Coffee ($4.99)" onPress={handleAddCoffee} />
125
251
  <Button title="Add Full Order" onPress={handleAddFullOrder} />
126
252
 
127
- {items.map((item, i) => (
128
- <View key={i}>
129
- <Text>{item.label}: ${item.amount}</Text>
130
- <Button title="Remove" onPress={() => removeItem(i)} />
253
+ {items.map((item, index) => (
254
+ <View key={index} style={{ flexDirection: 'row', padding: 10 }}>
255
+ <Text>{item.label}: ${item.amount.toFixed(2)}</Text>
256
+ <Button title="Remove" onPress={() => removeItem(index)} />
131
257
  </View>
132
258
  ))}
133
259
 
134
- <Text>Total: ${total.toFixed(2)}</Text>
260
+ <Text style={{ fontSize: 20, marginVertical: 10 }}>
261
+ Total: ${total.toFixed(2)}
262
+ </Text>
135
263
 
136
- {error && <Text style={{ color: 'red' }}>{error.message}</Text>}
264
+ {error && (
265
+ <Text style={{ color: 'red', marginVertical: 10 }}>
266
+ Error: {error.message}
267
+ </Text>
268
+ )}
137
269
 
138
270
  {isProcessing ? (
139
- <ActivityIndicator />
271
+ <ActivityIndicator size="large" />
140
272
  ) : (
141
273
  Platform.OS === 'ios' ? (
142
- <ApplePayButton onPress={handlePay} buttonType="buy" buttonStyle="black" />
274
+ <ApplePayButton
275
+ buttonType="buy"
276
+ buttonStyle="black"
277
+ onPress={handlePay}
278
+ style={{ width: '100%', height: 48 }}
279
+ />
143
280
  ) : (
144
- <GooglePayButton onPress={handlePay} buttonType="buy" theme="dark" />
281
+ <GooglePayButton
282
+ buttonType="buy"
283
+ theme="dark"
284
+ radius={4}
285
+ onPress={handlePay}
286
+ style={{ width: '100%', height: 48 }}
287
+ />
145
288
  )
146
289
  )}
147
290
  </View>
148
291
  )
149
292
  }
293
+
294
+ export default CheckoutScreen
150
295
  ```
151
296
 
152
- ### Basic Payment Flow (Without Hooks)
297
+ ---
153
298
 
154
- ```typescript
155
- import {
156
- HybridPaymentHandler,
157
- ApplePayButton,
158
- GooglePayButton,
159
- createPaymentRequest,
160
- } from 'react-native-pay'
161
- import { Platform } from 'react-native'
299
+ ## Documentation
162
300
 
163
- // Check if payment service is available
164
- const status = HybridPaymentHandler.payServiceStatus()
165
- console.log('Can make payments:', status.canMakePayments)
301
+ ### Payment Flow Overview
166
302
 
167
- // Create a payment request
168
- const paymentRequest = createPaymentRequest({
303
+ ```
304
+ 1. Check availability → usePaymentCheckout() or HybridPaymentHandler.payServiceStatus()
305
+ 2. Build cart → addItem() / addItems()
306
+ 3. Display payment button → ApplePayButton / GooglePayButton
307
+ 4. Process payment → startPayment()
308
+ 5. Handle result → Send token to server
309
+ 6. Complete transaction → Server processes with payment gateway
310
+ ```
311
+
312
+ ### Google Pay Configuration
313
+
314
+ For Google Pay, you need to configure your payment gateway:
315
+
316
+ ```typescript
317
+ const checkout = usePaymentCheckout({
169
318
  merchantIdentifier: 'merchant.com.yourcompany.app',
170
- amount: 29.99,
171
- label: 'Coffee Subscription',
172
- countryCode: 'US',
173
319
  currencyCode: 'USD',
174
- // Google Pay specific (optional)
320
+ countryCode: 'US',
321
+ // Google Pay specific
175
322
  googlePayEnvironment: 'TEST', // or 'PRODUCTION'
176
323
  googlePayGateway: 'stripe',
177
- googlePayGatewayMerchantId: 'your_gateway_merchant_id',
324
+ googlePayGatewayMerchantId: 'your_stripe_merchant_id',
178
325
  })
179
-
180
- // Handle payment
181
- const handlePayment = async () => {
182
- try {
183
- const result = await HybridPaymentHandler.startPayment(paymentRequest)
184
-
185
- if (result.success) {
186
- console.log('Payment successful:', result.transactionId)
187
- console.log('Payment token:', result.token)
188
- // Send token to your server for processing
189
- } else {
190
- console.error('Payment failed:', result.error)
191
- }
192
- } catch (error) {
193
- console.error('Payment error:', error)
194
- }
195
- }
196
-
197
- // Render platform-specific button
198
- {Platform.OS === 'ios' ? (
199
- <ApplePayButton
200
- buttonType="buy"
201
- buttonStyle="black"
202
- onPress={handlePayment}
203
- style={{ width: '100%', height: 48 }}
204
- />
205
- ) : (
206
- <GooglePayButton
207
- buttonType="buy"
208
- theme="dark"
209
- radius={4}
210
- onPress={handlePayment}
211
- style={{ width: '100%', height: 48 }}
212
- />
213
- )}
214
326
  ```
215
327
 
216
- ### Payment Request Configuration
328
+ #### Supported Payment Gateways
217
329
 
218
- ```typescript
219
- interface PaymentRequest {
220
- merchantIdentifier: string
221
- countryCode: string
222
- currencyCode: string
223
- paymentItems: PaymentItem[]
224
- merchantCapabilities: string[]
225
- supportedNetworks: string[]
226
- shippingType?: string
227
- shippingMethods?: PaymentItem[]
228
- billingContactRequired?: boolean
229
- shippingContactRequired?: boolean
230
- // Google Pay specific (Android only)
231
- googlePayEnvironment?: 'TEST' | 'PRODUCTION'
232
- googlePayGateway?: string
233
- googlePayGatewayMerchantId?: string
234
- }
235
- ```
236
-
237
- ### Utility Helpers
330
+ - **Stripe** - `googlePayGateway: 'stripe'`
331
+ - **Braintree** - `googlePayGateway: 'braintree'`
332
+ - **Square** - `googlePayGateway: 'square'`
333
+ - **Adyen** - `googlePayGateway: 'adyen'`
334
+ - **Authorize.net** - `googlePayGateway: 'authorizenet'`
335
+ - **Checkout.com** - `googlePayGateway: 'checkoutltd'`
238
336
 
239
- The package includes helpful utilities for common operations:
337
+ For the complete list, see [Google Pay Gateway Tokens](https://developers.google.com/pay/api/android/reference/request-objects#gateway).
240
338
 
241
- ```typescript
242
- import {
243
- createPaymentItem,
244
- calculateTotal,
245
- formatNetworkName,
246
- } from 'react-native-pay'
247
-
248
- // Create payment items
249
- const item1 = createPaymentItem('Subscription', 29.99, 'final')
250
- const item2 = createPaymentItem('Tax', 2.4, 'final')
251
-
252
- // Calculate total
253
- const total = calculateTotal([item1, item2]) // 32.39
254
-
255
- // Format network names
256
- formatNetworkName('visa') // "Visa"
257
- formatNetworkName('amex') // "American Express"
258
- ```
339
+ ---
259
340
 
260
341
  ## API Reference
261
342
 
262
- ### React Hook
263
-
264
- #### `usePaymentCheckout(config)`
343
+ ### `usePaymentCheckout(config)`
265
344
 
266
- All-in-one hook for payment checkout flow.
345
+ The all-in-one hook for handling payments. Manages availability checking, cart state, and payment processing.
267
346
 
268
- **Configuration:**
347
+ #### Configuration
269
348
 
270
349
  ```typescript
271
- {
350
+ interface UsePaymentCheckoutConfig {
272
351
  merchantIdentifier: string
273
- countryCode?: string // Default: 'US'
274
- currencyCode?: string // Default: 'USD'
275
- supportedNetworks?: string[] // Default: ['visa', 'mastercard', 'amex', 'discover']
276
- merchantCapabilities?: string[] // Default: ['3DS']
352
+ merchantName?: string
353
+ countryCode?: string // Default: 'US'
354
+ currencyCode?: string // Default: 'USD'
355
+ supportedNetworks?: string[] // Default: ['visa', 'mastercard', 'amex', 'discover']
356
+ merchantCapabilities?: string[] // Default: ['3DS']
357
+ // Google Pay specific (Android)
277
358
  googlePayEnvironment?: 'TEST' | 'PRODUCTION'
278
359
  googlePayGateway?: string
279
360
  googlePayGatewayMerchantId?: string
280
361
  }
281
362
  ```
282
363
 
283
- **Returns:**
364
+ #### Returns
284
365
 
285
366
  ```typescript
286
- {
367
+ interface UsePaymentCheckoutReturn {
287
368
  // Payment availability
288
- canMakePayments: boolean
289
- canSetupCards: boolean
290
- isCheckingStatus: boolean
369
+ canMakePayments: boolean // Can user make payments?
370
+ canSetupCards: boolean // Can user add cards?
371
+ isCheckingStatus: boolean // Loading state for availability check
291
372
 
292
373
  // Cart management
293
- items: PaymentItem[]
294
- total: number
374
+ items: PaymentItem[] // Current cart items
375
+ total: number // Total amount
295
376
  addItem: (label: string, amount: number, type?: 'final' | 'pending') => void
296
- addItems: (items: Array<{ label, amount, type? }>) => void // Add multiple at once
377
+ addItems: (items: Array<{ label; amount; type? }>) => void
297
378
  removeItem: (index: number) => void
298
379
  updateItem: (index: number, updates: Partial<PaymentItem>) => void
299
380
  clearItems: () => void
300
381
 
301
382
  // Payment processing
302
383
  startPayment: () => Promise<PaymentResult | null>
303
- isProcessing: boolean
304
- result: PaymentResult | null
305
- error: Error | null
384
+ isProcessing: boolean // Payment in progress?
385
+ result: PaymentResult | null // Last payment result
386
+ error: Error | null // Last error
306
387
 
307
388
  // Utilities
308
- reset: () => void
309
- paymentRequest: PaymentRequest // Full request object
389
+ reset: () => void // Reset payment state
390
+ paymentRequest: PaymentRequest // Full request object
310
391
  }
311
392
  ```
312
393
 
313
- **Example:**
394
+ #### Example
314
395
 
315
396
  ```typescript
316
397
  const checkout = usePaymentCheckout({
317
398
  merchantIdentifier: 'merchant.com.example',
318
399
  currencyCode: 'USD',
319
400
  countryCode: 'US',
401
+ googlePayEnvironment: 'TEST',
402
+ googlePayGateway: 'stripe',
403
+ googlePayGatewayMerchantId: 'your_stripe_merchant_id',
320
404
  })
321
405
 
322
406
  // Add single item
@@ -329,127 +413,718 @@ checkout.addItems([
329
413
  { label: 'Tax', amount: 2.8, type: 'final' },
330
414
  ])
331
415
 
332
- // Check total
333
- console.log(checkout.total) // 37.79
334
-
335
416
  // Process payment
336
417
  const result = await checkout.startPayment()
337
- if (result?.success) {
338
- // Handle success
339
- }
340
418
  ```
341
419
 
342
- ### HybridPaymentHandler
420
+ ---
421
+
422
+ ### `HybridPaymentHandler`
343
423
 
344
- #### `payServiceStatus(): PayServiceStatus`
424
+ Low-level payment handler for direct control.
345
425
 
346
- Returns the current payment service availability.
426
+ #### Methods
427
+
428
+ ##### `payServiceStatus(): PayServiceStatus`
429
+
430
+ Check payment service availability.
347
431
 
348
432
  ```typescript
349
433
  const status = HybridPaymentHandler.payServiceStatus()
350
- console.log(status.canMakePayments) // boolean
351
- console.log(status.canSetupCards) // boolean
434
+ console.log('Can make payments:', status.canMakePayments)
435
+ console.log('Can setup cards:', status.canSetupCards)
436
+ ```
437
+
438
+ **Returns:**
439
+
440
+ ```typescript
441
+ interface PayServiceStatus {
442
+ canMakePayments: boolean
443
+ canSetupCards: boolean
444
+ }
352
445
  ```
353
446
 
354
- #### `startPayment(request: PaymentRequest): Promise<PaymentResult>`
447
+ ##### `startPayment(request: PaymentRequest): Promise<PaymentResult>`
355
448
 
356
- Initiates a payment request.
449
+ Start a payment request.
357
450
 
358
451
  ```typescript
359
- const result = await HybridPaymentHandler.startPayment(paymentRequest)
452
+ const result = await HybridPaymentHandler.startPayment({
453
+ merchantIdentifier: 'merchant.com.example',
454
+ countryCode: 'US',
455
+ currencyCode: 'USD',
456
+ merchantCapabilities: ['3DS'],
457
+ supportedNetworks: ['visa', 'mastercard', 'amex'],
458
+ paymentItems: [{ label: 'Total', amount: 29.99, type: 'final' }],
459
+ })
460
+ ```
461
+
462
+ **Returns:**
463
+
464
+ ```typescript
465
+ interface PaymentResult {
466
+ success: boolean
467
+ transactionId?: string
468
+ token?: PaymentToken
469
+ error?: string
470
+ }
471
+
472
+ interface PaymentToken {
473
+ paymentMethod: PaymentMethod
474
+ transactionIdentifier: string
475
+ paymentData: string // Base64 encoded
476
+ }
360
477
  ```
361
478
 
362
- #### `canMakePayments(usingNetworks: string[]): boolean`
479
+ ##### `canMakePayments(usingNetworks: string[]): boolean`
363
480
 
364
- Checks if the device can make payments using specific networks.
481
+ Check if specific card networks are supported.
365
482
 
366
483
  ```typescript
367
484
  const canPay = HybridPaymentHandler.canMakePayments(['visa', 'mastercard'])
368
485
  ```
369
486
 
487
+ ---
488
+
370
489
  ### Button Components
371
490
 
372
- #### ApplePayButton (iOS)
491
+ #### `ApplePayButton` (iOS)
492
+
493
+ Native Apple Pay button with full customization.
494
+
495
+ ##### Props
496
+
497
+ ```typescript
498
+ interface ApplePayButtonProps {
499
+ buttonType?:
500
+ | 'plain'
501
+ | 'buy'
502
+ | 'setUp'
503
+ | 'inStore'
504
+ | 'donate'
505
+ | 'checkout'
506
+ | 'book'
507
+ | 'subscribe'
508
+ | 'reload'
509
+ | 'addMoney'
510
+ | 'topUp'
511
+ | 'order'
512
+ | 'rent'
513
+ | 'support'
514
+ | 'contribute'
515
+ | 'tip'
516
+
517
+ buttonStyle?: 'white' | 'whiteOutline' | 'black' | 'automatic'
518
+
519
+ onPress: () => void
520
+ style?: ViewStyle
521
+ }
522
+ ```
523
+
524
+ ##### Example
373
525
 
374
526
  ```typescript
375
527
  <ApplePayButton
376
- buttonType="buy" | "setup" | "book" | "donate" | "order" | "continue" | ...
377
- buttonStyle="white" | "black" | "whiteOutline" | "automatic"
378
- onPress={() => handlePayment()}
379
- style={styles.button}
528
+ buttonType="buy"
529
+ buttonStyle="black"
530
+ onPress={handlePayment}
531
+ style={{ width: '100%', height: 48 }}
380
532
  />
381
533
  ```
382
534
 
383
- #### GooglePayButton (Android)
535
+ #### `GooglePayButton` (Android)
536
+
537
+ Native Google Pay button with customization.
538
+
539
+ ##### Props
540
+
541
+ ```typescript
542
+ interface GooglePayButtonProps {
543
+ buttonType?:
544
+ | 'buy'
545
+ | 'book'
546
+ | 'checkout'
547
+ | 'donate'
548
+ | 'order'
549
+ | 'pay'
550
+ | 'subscribe'
551
+ | 'plain'
552
+
553
+ theme?: 'dark' | 'light'
554
+
555
+ radius?: number // Corner radius in dp
556
+
557
+ onPress: () => void
558
+ style?: ViewStyle
559
+ }
560
+ ```
561
+
562
+ ##### Example
384
563
 
385
564
  ```typescript
386
565
  <GooglePayButton
387
- buttonType="buy" | "book" | "checkout" | "donate" | "order" | "pay" | "subscribe" | "plain"
388
- theme="dark" | "light"
389
- radius={4} // optional corner radius
390
- onPress={() => handlePayment()}
391
- style={styles.button}
566
+ buttonType="buy"
567
+ theme="dark"
568
+ radius={8}
569
+ onPress={handlePayment}
570
+ style={{ width: '100%', height: 48 }}
392
571
  />
393
572
  ```
394
573
 
574
+ ---
575
+
576
+ ### Utility Functions
577
+
578
+ #### `createPaymentRequest(config)`
579
+
580
+ Create a complete payment request from simplified config.
581
+
582
+ ```typescript
583
+ import { createPaymentRequest } from '@gmisoftware/react-native-pay'
584
+
585
+ const request = createPaymentRequest({
586
+ merchantIdentifier: 'merchant.com.example',
587
+ amount: 29.99,
588
+ label: 'Coffee Subscription',
589
+ countryCode: 'US',
590
+ currencyCode: 'USD',
591
+ googlePayEnvironment: 'TEST',
592
+ googlePayGateway: 'stripe',
593
+ googlePayGatewayMerchantId: 'your_merchant_id',
594
+ })
595
+ ```
596
+
597
+ #### `createPaymentItem(label, amount, type)`
598
+
599
+ Create a payment item.
600
+
601
+ ```typescript
602
+ import { createPaymentItem } from '@gmisoftware/react-native-pay'
603
+
604
+ const item = createPaymentItem('Subscription', 29.99, 'final')
605
+ // { label: 'Subscription', amount: 29.99, type: 'final' }
606
+ ```
607
+
608
+ #### `calculateTotal(items)`
609
+
610
+ Calculate total from payment items.
611
+
612
+ ```typescript
613
+ import { calculateTotal } from '@gmisoftware/react-native-pay'
614
+
615
+ const items = [
616
+ { label: 'Product', amount: 29.99, type: 'final' },
617
+ { label: 'Tax', amount: 2.4, type: 'final' },
618
+ ]
619
+
620
+ const total = calculateTotal(items) // 32.39
621
+ ```
622
+
623
+ #### `formatNetworkName(network)`
624
+
625
+ Format card network name for display.
626
+
627
+ ```typescript
628
+ import { formatNetworkName } from '@gmisoftware/react-native-pay'
629
+
630
+ formatNetworkName('visa') // "Visa"
631
+ formatNetworkName('mastercard') // "Mastercard"
632
+ formatNetworkName('amex') // "American Express"
633
+ ```
634
+
635
+ ---
636
+
637
+ ## TypeScript Types
638
+
639
+ ### Core Types
640
+
641
+ ```typescript
642
+ // Payment Item
643
+ interface PaymentItem {
644
+ label: string
645
+ amount: number
646
+ type: 'final' | 'pending'
647
+ }
648
+
649
+ // Payment Request
650
+ interface PaymentRequest {
651
+ merchantIdentifier: string
652
+ merchantName?: string
653
+ countryCode: string
654
+ currencyCode: string
655
+ paymentItems: PaymentItem[]
656
+ merchantCapabilities: string[]
657
+ supportedNetworks: string[]
658
+ shippingType?: string
659
+ shippingMethods?: PaymentItem[]
660
+ billingContactRequired?: boolean
661
+ shippingContactRequired?: boolean
662
+ // Google Pay specific
663
+ googlePayEnvironment?: 'TEST' | 'PRODUCTION'
664
+ googlePayGateway?: string
665
+ googlePayGatewayMerchantId?: string
666
+ }
667
+
668
+ // Payment Result
669
+ interface PaymentResult {
670
+ success: boolean
671
+ transactionId?: string
672
+ token?: PaymentToken
673
+ error?: string
674
+ }
675
+
676
+ // Payment Token
677
+ interface PaymentToken {
678
+ paymentMethod: PaymentMethod
679
+ transactionIdentifier: string
680
+ paymentData: string // Base64 encoded
681
+ }
682
+
683
+ // Payment Method
684
+ interface PaymentMethod {
685
+ displayName?: string
686
+ network?: PaymentNetwork
687
+ type: PaymentMethodType
688
+ secureElementPass?: PKSecureElementPass
689
+ billingAddress?: CNContact
690
+ }
691
+
692
+ // Payment Networks
693
+ type PaymentNetwork =
694
+ | 'visa'
695
+ | 'mastercard'
696
+ | 'amex'
697
+ | 'discover'
698
+ | 'jcb'
699
+ | 'maestro'
700
+ | 'electron'
701
+ | 'elo'
702
+ | 'idcredit'
703
+ | 'interac'
704
+ | 'privateLabel'
705
+
706
+ // Payment Method Type
707
+ type PaymentMethodType = 'unknown' | 'debit' | 'credit' | 'prepaid' | 'store'
708
+ ```
709
+
710
+ ### Contact Types
711
+
712
+ ```typescript
713
+ interface CNContact {
714
+ identifier: string
715
+ contactType: 'person' | 'organization'
716
+ namePrefix: string
717
+ givenName: string
718
+ middleName: string
719
+ familyName: string
720
+ previousFamilyName: string
721
+ nameSuffix: string
722
+ nickname: string
723
+ organizationName: string
724
+ departmentName: string
725
+ jobTitle: string
726
+ phoneticGivenName: string
727
+ phoneticMiddleName: string
728
+ phoneticFamilyName: string
729
+ phoneticOrganizationName?: string
730
+ note: string
731
+ imageDataAvailable?: boolean
732
+ phoneNumbers: CNLabeledPhoneNumber[]
733
+ emailAddresses: CNLabeledEmailAddress[]
734
+ postalAddresses: CNLabeledPostalAddress[]
735
+ }
736
+
737
+ interface CNPostalAddress {
738
+ street?: string
739
+ city?: string
740
+ state?: string
741
+ postalCode?: string
742
+ country?: string
743
+ isoCountryCode?: string
744
+ }
745
+ ```
746
+
747
+ ---
748
+
749
+ ## Advanced Usage
750
+
751
+ ### Manual Payment Flow (Without Hook)
752
+
753
+ For advanced use cases where you need more control:
754
+
755
+ ```typescript
756
+ import {
757
+ HybridPaymentHandler,
758
+ createPaymentRequest,
759
+ ApplePayButton,
760
+ GooglePayButton,
761
+ } from '@gmisoftware/react-native-pay'
762
+ import { Platform } from 'react-native'
763
+
764
+ // 1. Check availability
765
+ const status = HybridPaymentHandler.payServiceStatus()
766
+ if (!status.canMakePayments) {
767
+ console.log('Payment not available')
768
+ return
769
+ }
770
+
771
+ // 2. Create payment request
772
+ const paymentRequest = createPaymentRequest({
773
+ merchantIdentifier: 'merchant.com.example',
774
+ amount: 99.99,
775
+ label: 'Premium Subscription',
776
+ countryCode: 'US',
777
+ currencyCode: 'USD',
778
+ googlePayEnvironment: 'PRODUCTION',
779
+ googlePayGateway: 'stripe',
780
+ googlePayGatewayMerchantId: 'your_merchant_id',
781
+ })
782
+
783
+ // 3. Handle payment
784
+ const handlePayment = async () => {
785
+ try {
786
+ const result = await HybridPaymentHandler.startPayment(paymentRequest)
787
+
788
+ if (result.success && result.token) {
789
+ // Send to your server
790
+ await processPaymentOnServer(result.token)
791
+ } else {
792
+ console.error('Payment failed:', result.error)
793
+ }
794
+ } catch (error) {
795
+ console.error('Payment error:', error)
796
+ }
797
+ }
798
+
799
+ // 4. Render button
800
+ return Platform.OS === 'ios' ? (
801
+ <ApplePayButton
802
+ buttonType="subscribe"
803
+ buttonStyle="black"
804
+ onPress={handlePayment}
805
+ />
806
+ ) : (
807
+ <GooglePayButton
808
+ buttonType="subscribe"
809
+ theme="dark"
810
+ onPress={handlePayment}
811
+ />
812
+ )
813
+ ```
814
+
815
+ ### Dynamic Cart Management
816
+
817
+ ```typescript
818
+ const checkout = usePaymentCheckout({
819
+ merchantIdentifier: 'merchant.com.example',
820
+ currencyCode: 'USD',
821
+ })
822
+
823
+ // Add items dynamically
824
+ const handleAddToCart = (product) => {
825
+ checkout.addItem(product.name, product.price)
826
+ }
827
+
828
+ // Update quantity
829
+ const handleUpdateQuantity = (index, quantity) => {
830
+ const item = checkout.items[index]
831
+ checkout.updateItem(index, {
832
+ amount: item.amount * quantity,
833
+ })
834
+ }
835
+
836
+ // Apply discount
837
+ const handleApplyDiscount = (discountPercent) => {
838
+ const discountAmount = checkout.total * (discountPercent / 100)
839
+ checkout.addItem('Discount', -discountAmount, 'final')
840
+ }
841
+
842
+ // Clear cart
843
+ const handleClearCart = () => {
844
+ checkout.clearItems()
845
+ }
846
+ ```
847
+
848
+ ### Custom Payment Buttons
849
+
850
+ Create your own styled buttons:
851
+
852
+ ```typescript
853
+ import { Pressable, Text } from 'react-native'
854
+
855
+ function CustomPayButton({ onPress }) {
856
+ return (
857
+ <Pressable
858
+ onPress={onPress}
859
+ style={{
860
+ backgroundColor: '#000',
861
+ padding: 16,
862
+ borderRadius: 8,
863
+ alignItems: 'center',
864
+ }}
865
+ >
866
+ <Text style={{ color: '#fff', fontWeight: 'bold' }}>
867
+ {Platform.OS === 'ios' ? ' Pay' : 'G Pay'}
868
+ </Text>
869
+ </Pressable>
870
+ )
871
+ }
872
+
873
+ // Use it
874
+ <CustomPayButton onPress={handlePayment} />
875
+ ```
876
+
877
+ ### Server-Side Processing
878
+
879
+ After receiving the payment token, process it on your server:
880
+
881
+ #### Node.js + Stripe Example
882
+
883
+ ```javascript
884
+ // Backend API endpoint
885
+ app.post('/process-payment', async (req, res) => {
886
+ const { token } = req.body
887
+
888
+ try {
889
+ // For Apple Pay
890
+ if (token.paymentData) {
891
+ const charge = await stripe.charges.create({
892
+ amount: 2999, // $29.99
893
+ currency: 'usd',
894
+ source: token.paymentData, // Apple Pay token
895
+ description: 'Payment from React Native Pay',
896
+ })
897
+ }
898
+
899
+ // For Google Pay
900
+ // The token format depends on your gateway
901
+
902
+ res.json({ success: true, chargeId: charge.id })
903
+ } catch (error) {
904
+ res.status(500).json({ error: error.message })
905
+ }
906
+ })
907
+ ```
908
+
909
+ ---
910
+
395
911
  ## Architecture
396
912
 
397
913
  ### Package Structure
398
914
 
399
915
  ```
400
- package/
916
+ @gmisoftware/react-native-pay/
401
917
  ├── android/ # Android implementation
402
- └── src/main/java/com/.../pay/
403
- ├── Constants.kt # Shared constants
404
- ├── GooglePayButtonFactory.kt # Button creation utility
405
- ├── GooglePayRequestBuilder.kt # Payment request builder
406
- ├── HybridGooglePayButton.kt # Button component
407
- ├── HybridPaymentHandler.kt # Payment handler
408
- ├── NitroPayPackage.kt # RN package
409
- └── PaymentMapper.kt # Data mapper
918
+ ├── src/main/java/com/margelo/nitro/pay/
919
+ ├── Constants.kt # Shared constants
920
+ ├── GooglePayButtonFactory.kt # Button factory
921
+ ├── GooglePayRequestBuilder.kt # Request builder
922
+ ├── HybridGooglePayButton.kt # Button component
923
+ ├── HybridPaymentHandler.kt # Payment handler
924
+ │ └── PaymentMapper.kt # Data transformation
925
+ ├── build.gradle
926
+ │ └── CMakeLists.txt
927
+
410
928
  ├── ios/ # iOS implementation
411
- │ ├── ApplePayButtonFactory.swift # Button creation utility
929
+ │ ├── ApplePayButtonFactory.swift # Button factory
412
930
  │ ├── HybridApplePayButton.swift # Button component
413
931
  │ ├── HybridPaymentHandler.swift # Payment handler
414
- │ └── PassKitTypeMapper.swift # Type converter
415
- ├── src/ # TypeScript/JavaScript
416
- ├── specs/ # Nitro type specs
932
+ │ └── PassKitTypeMapper.swift # Type conversion
933
+
934
+ ├── src/ # TypeScript source
935
+ │ ├── specs/ # Nitro specifications
417
936
  │ │ ├── ApplePayButton.nitro.ts
418
937
  │ │ ├── GooglePayButton.nitro.ts
419
938
  │ │ └── PaymentHandler.nitro.ts
420
939
  │ ├── types/ # Type definitions
421
- │ │ ├── Contact.ts
422
- │ │ └── Payment.ts
423
- ├── utils/ # Utility helpers
424
- │ └── paymentHelpers.ts
940
+ │ │ ├── Contact.ts # Contact types
941
+ │ │ ├── Payment.ts # Payment types
942
+ │ └── index.ts
943
+ ├── utils/ # Utilities
944
+ │ │ ├── paymentHelpers.ts
945
+ │ │ └── index.ts
946
+ │ ├── hooks/ # React hooks
947
+ │ │ ├── usePaymentCheckout.ts
948
+ │ │ └── index.ts
425
949
  │ ├── plugin/ # Expo config plugins
426
950
  │ │ ├── withApplePay.ts
427
- │ │ └── withGooglePay.ts
951
+ │ │ ├── withGooglePay.ts
952
+ │ │ └── index.ts
428
953
  │ └── index.ts # Public API
429
- └── nitrogen/ # Generated code (auto-generated)
954
+
955
+ ├── nitrogen/ # Generated code
956
+ │ └── generated/
957
+ │ ├── android/
958
+ │ ├── ios/
959
+ │ └── shared/
960
+
961
+ └── package.json
430
962
  ```
431
963
 
432
964
  ### Design Principles
433
965
 
434
- 1. **Separation of Concerns**: Each component has a single, well-defined responsibility
435
- 2. **Factory Pattern**: Button and request creation abstracted into factory classes
436
- 3. **Type Safety**: Comprehensive TypeScript definitions with runtime validation
437
- 4. **Code Reusability**: Shared utilities and helpers reduce duplication
438
- 5. **Platform Consistency**: Unified API abstracts platform differences
966
+ 1. **Platform Abstraction** - Single API for both iOS and Android
967
+ 2. **Type Safety** - Full TypeScript coverage with runtime validation
968
+ 3. **Performance** - Built with Nitro Modules for native speed
969
+ 4. **Developer Experience** - Simple hooks API with sensible defaults
970
+ 5. **Production Ready** - Battle-tested in real-world applications
971
+
972
+ ---
973
+
974
+ ## Troubleshooting
975
+
976
+ ### iOS Issues
977
+
978
+ #### Apple Pay button not showing
979
+
980
+ - Verify merchant ID is correctly configured in Apple Developer Portal
981
+ - Check that entitlements are properly set in your Xcode project
982
+ - Ensure you've run `npx expo prebuild --clean`
983
+ - Test on a real device (Simulator requires additional setup)
984
+
985
+ #### "Cannot make payments" error
986
+
987
+ - Add a card to Apple Wallet on your test device
988
+ - Verify your merchant ID matches exactly
989
+ - Check that Apple Pay is enabled in Settings > Wallet & Apple Pay
990
+
991
+ ### Android Issues
992
+
993
+ #### Google Pay button not showing
994
+
995
+ - Verify Google Pay is enabled in your AndroidManifest.xml
996
+ - Check that `enableGooglePay: true` is set in your plugin config
997
+ - Ensure Google Play Services is installed on the device
998
+ - Test with a real device (Emulator needs Google Play Services)
999
+
1000
+ #### "Google Pay unavailable" error
1001
+
1002
+ - Add a card to Google Pay on your test device
1003
+ - For testing, use `googlePayEnvironment: 'TEST'`
1004
+ - Verify your gateway configuration is correct
1005
+
1006
+ ### General Issues
1007
+
1008
+ #### Build errors with Nitro
1009
+
1010
+ ```bash
1011
+ # Clean and reinstall
1012
+ rm -rf node_modules
1013
+ rm -rf ios/Pods ios/build
1014
+ rm -rf android/build android/app/build
1015
+ npm install
1016
+ cd ios && pod install
1017
+ ```
1018
+
1019
+ #### Type errors
1020
+
1021
+ ```bash
1022
+ # Regenerate types
1023
+ cd package
1024
+ npm run typescript
1025
+ npm run specs
1026
+ ```
1027
+
1028
+ ---
1029
+
1030
+ ## Examples
1031
+
1032
+ Check out the `/example` directory for a complete working implementation with:
1033
+
1034
+ - Full checkout flow
1035
+ - Cart management
1036
+ - Error handling
1037
+ - Platform-specific UI
1038
+
1039
+ Run the example:
1040
+
1041
+ ```bash
1042
+ cd example
1043
+ npm install
1044
+ npx expo prebuild
1045
+ npx expo run:ios
1046
+ npx expo run:android
1047
+ ```
1048
+
1049
+ ---
439
1050
 
440
1051
  ## Contributing
441
1052
 
442
- Contributions are welcome! Please ensure:
1053
+ We welcome contributions! Please follow these guidelines:
443
1054
 
444
- - Code follows existing patterns and style
445
- - All TypeScript types are properly defined
446
- - Native code is properly documented
447
- - Tests pass (when available)
1055
+ ### Development Setup
1056
+
1057
+ ```bash
1058
+ # Clone the repository
1059
+ git clone https://github.com/gmi-software/react-native-pay.git
1060
+ cd react-native-pay
1061
+
1062
+ # Install dependencies
1063
+ npm install
1064
+ cd package && npm install
1065
+
1066
+ # Generate Nitro bindings
1067
+ cd package
1068
+ npm run specs
1069
+ ```
1070
+
1071
+ ### Code Style
1072
+
1073
+ - Follow existing TypeScript patterns
1074
+ - Add JSDoc comments for public APIs
1075
+ - Use Prettier for formatting (runs automatically)
1076
+ - Ensure types are properly exported
1077
+
1078
+ ### Testing
1079
+
1080
+ - Test on both iOS and Android
1081
+ - Test with real devices (Simulator/Emulator support limited)
1082
+ - Verify in both TEST and PRODUCTION modes
1083
+
1084
+ ### Pull Requests
1085
+
1086
+ - Create a feature branch from `main`
1087
+ - Write descriptive commit messages
1088
+ - Update documentation for API changes
1089
+ - Add examples for new features
1090
+
1091
+ ---
1092
+
1093
+ ## Roadmap
1094
+
1095
+ - [ ] Recurring payment support
1096
+ - [ ] Shipping address collection
1097
+ - [ ] Multi-currency support
1098
+ - [ ] Payment request validation
1099
+ - [ ] Automated testing suite
1100
+ - [ ] Detailed transaction logging
1101
+ - [ ] Web support (via Payment Request API)
1102
+
1103
+ ---
448
1104
 
449
1105
  ## License
450
1106
 
451
- MIT
1107
+ MIT © [GMI Software](https://gmi.software)
1108
+
1109
+ ---
452
1110
 
453
1111
  ## Credits
454
1112
 
455
- Built with [Nitro Modules](https://nitro.margelo.com/) by [Margelo](https://margelo.com/)
1113
+ - Built with [Nitro Modules](https://nitro.margelo.com/) by [Margelo](https://margelo.com/)
1114
+ - Developed by [GMI Software](https://gmi.software)
1115
+
1116
+ ---
1117
+
1118
+ ## Support
1119
+
1120
+ - 📧 Email: [support@gmi.software](mailto:support@gmi.software)
1121
+ - 🐛 Issues: [GitHub Issues](https://github.com/gmi-software/react-native-pay/issues)
1122
+ - 💬 Discussions: [GitHub Discussions](https://github.com/gmi-software/react-native-pay/discussions)
1123
+
1124
+ ---
1125
+
1126
+ <div align="center">
1127
+
1128
+ Made with ❤️ by [GMI Software](https://gmi.software)
1129
+
1130
+ </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmisoftware/react-native-pay",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "author": "gmi.software",
5
5
  "repository": {
6
6
  "type": "git",
@@ -103,6 +103,8 @@
103
103
  },
104
104
  "react-native": "src/index",
105
105
  "scripts": {
106
+ "prepack": "cp ../README.md ./README.md",
107
+ "postpack": "rm ./README.md",
106
108
  "postinstall": "tsc || exit 0;",
107
109
  "typecheck": "tsc --noEmit",
108
110
  "clean": "rm -rf android/build node_modules/**/android/build lib",
@@ -113,4 +115,4 @@
113
115
  },
114
116
  "source": "src/index",
115
117
  "types": "lib/index.d.ts"
116
- }
118
+ }