@gmisoftware/react-native-pay 0.0.10 → 0.0.12
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.
- package/README.md +1130 -0
- package/package.json +8 -7
package/README.md
ADDED
|
@@ -0,0 +1,1130 @@
|
|
|
1
|
+
# React Native Pay
|
|
2
|
+
|
|
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
|
+
[](https://www.npmjs.com/package/@gmisoftware/react-native-pay)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://www.typescriptlang.org/)
|
|
10
|
+
[](https://expo.dev/)
|
|
11
|
+
|
|
12
|
+
Built with [Nitro Modules](https://nitro.margelo.com/) for high-performance native integration.
|
|
13
|
+
|
|
14
|
+
[Features](#features) • [Installation](#installation) • [Quick Start](#quick-start) • [Documentation](#documentation) • [API Reference](#api-reference)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
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
|
|
28
|
+
- ✅ **Modern Architecture** - Built with Nitro Modules for optimal performance
|
|
29
|
+
- ✅ **Expo Compatible** - Config plugins for seamless Expo integration
|
|
30
|
+
- ✅ **Production Ready** - Used in production apps with millions of transactions
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
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
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install @gmisoftware/react-native-pay
|
|
52
|
+
# or
|
|
53
|
+
yarn add @gmisoftware/react-native-pay
|
|
54
|
+
# or
|
|
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
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Android Setup (Google Pay)
|
|
112
|
+
|
|
113
|
+
#### 1. Configure Expo Config Plugin
|
|
114
|
+
|
|
115
|
+
Add the Google Pay plugin to your `app.json` or `app.config.js`:
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
{
|
|
119
|
+
"expo": {
|
|
120
|
+
"plugins": [
|
|
121
|
+
[
|
|
122
|
+
"@gmisoftware/react-native-pay",
|
|
123
|
+
{
|
|
124
|
+
"enableGooglePay": true
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
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)
|
|
150
|
+
|
|
151
|
+
For apps supporting both platforms:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
{
|
|
155
|
+
"expo": {
|
|
156
|
+
"plugins": [
|
|
157
|
+
[
|
|
158
|
+
"@gmisoftware/react-native-pay",
|
|
159
|
+
{
|
|
160
|
+
"merchantIdentifier": "merchant.com.yourcompany.app",
|
|
161
|
+
"enableGooglePay": true
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Quick Start
|
|
172
|
+
|
|
173
|
+
### Basic Example with Hook (Recommended)
|
|
174
|
+
|
|
175
|
+
The easiest way to integrate payments - one hook handles everything:
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
import React from 'react'
|
|
179
|
+
import {
|
|
180
|
+
usePaymentCheckout,
|
|
181
|
+
ApplePayButton,
|
|
182
|
+
GooglePayButton,
|
|
183
|
+
} from '@gmisoftware/react-native-pay'
|
|
184
|
+
import { Platform, View, Text, Button, ActivityIndicator } from 'react-native'
|
|
185
|
+
|
|
186
|
+
function CheckoutScreen() {
|
|
187
|
+
const {
|
|
188
|
+
// Payment availability
|
|
189
|
+
canMakePayments,
|
|
190
|
+
|
|
191
|
+
// Cart management
|
|
192
|
+
items,
|
|
193
|
+
total,
|
|
194
|
+
addItem,
|
|
195
|
+
addItems,
|
|
196
|
+
removeItem,
|
|
197
|
+
|
|
198
|
+
// Payment processing
|
|
199
|
+
startPayment,
|
|
200
|
+
isProcessing,
|
|
201
|
+
error,
|
|
202
|
+
} = usePaymentCheckout({
|
|
203
|
+
merchantIdentifier: 'merchant.com.yourcompany.app',
|
|
204
|
+
currencyCode: 'USD',
|
|
205
|
+
countryCode: 'US',
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
const handleAddCoffee = () => {
|
|
209
|
+
addItem('Coffee', 4.99)
|
|
210
|
+
}
|
|
211
|
+
|
|
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
|
+
}
|
|
219
|
+
|
|
220
|
+
const handlePay = async () => {
|
|
221
|
+
const result = await startPayment()
|
|
222
|
+
|
|
223
|
+
if (result?.success && result.token) {
|
|
224
|
+
// Send result.token to your server for processing
|
|
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
|
+
})
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!canMakePayments) {
|
|
241
|
+
return (
|
|
242
|
+
<View>
|
|
243
|
+
<Text>Apple Pay or Google Pay is not available on this device</Text>
|
|
244
|
+
</View>
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<View style={{ padding: 20 }}>
|
|
250
|
+
<Button title="Add Coffee ($4.99)" onPress={handleAddCoffee} />
|
|
251
|
+
<Button title="Add Full Order" onPress={handleAddFullOrder} />
|
|
252
|
+
|
|
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)} />
|
|
257
|
+
</View>
|
|
258
|
+
))}
|
|
259
|
+
|
|
260
|
+
<Text style={{ fontSize: 20, marginVertical: 10 }}>
|
|
261
|
+
Total: ${total.toFixed(2)}
|
|
262
|
+
</Text>
|
|
263
|
+
|
|
264
|
+
{error && (
|
|
265
|
+
<Text style={{ color: 'red', marginVertical: 10 }}>
|
|
266
|
+
Error: {error.message}
|
|
267
|
+
</Text>
|
|
268
|
+
)}
|
|
269
|
+
|
|
270
|
+
{isProcessing ? (
|
|
271
|
+
<ActivityIndicator size="large" />
|
|
272
|
+
) : (
|
|
273
|
+
Platform.OS === 'ios' ? (
|
|
274
|
+
<ApplePayButton
|
|
275
|
+
buttonType="buy"
|
|
276
|
+
buttonStyle="black"
|
|
277
|
+
onPress={handlePay}
|
|
278
|
+
style={{ width: '100%', height: 48 }}
|
|
279
|
+
/>
|
|
280
|
+
) : (
|
|
281
|
+
<GooglePayButton
|
|
282
|
+
buttonType="buy"
|
|
283
|
+
theme="dark"
|
|
284
|
+
radius={4}
|
|
285
|
+
onPress={handlePay}
|
|
286
|
+
style={{ width: '100%', height: 48 }}
|
|
287
|
+
/>
|
|
288
|
+
)
|
|
289
|
+
)}
|
|
290
|
+
</View>
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export default CheckoutScreen
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Documentation
|
|
300
|
+
|
|
301
|
+
### Payment Flow Overview
|
|
302
|
+
|
|
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({
|
|
318
|
+
merchantIdentifier: 'merchant.com.yourcompany.app',
|
|
319
|
+
currencyCode: 'USD',
|
|
320
|
+
countryCode: 'US',
|
|
321
|
+
// Google Pay specific
|
|
322
|
+
googlePayEnvironment: 'TEST', // or 'PRODUCTION'
|
|
323
|
+
googlePayGateway: 'stripe',
|
|
324
|
+
googlePayGatewayMerchantId: 'your_stripe_merchant_id',
|
|
325
|
+
})
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
#### Supported Payment Gateways
|
|
329
|
+
|
|
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'`
|
|
336
|
+
|
|
337
|
+
For the complete list, see [Google Pay Gateway Tokens](https://developers.google.com/pay/api/android/reference/request-objects#gateway).
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## API Reference
|
|
342
|
+
|
|
343
|
+
### `usePaymentCheckout(config)`
|
|
344
|
+
|
|
345
|
+
The all-in-one hook for handling payments. Manages availability checking, cart state, and payment processing.
|
|
346
|
+
|
|
347
|
+
#### Configuration
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
interface UsePaymentCheckoutConfig {
|
|
351
|
+
merchantIdentifier: string
|
|
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)
|
|
358
|
+
googlePayEnvironment?: 'TEST' | 'PRODUCTION'
|
|
359
|
+
googlePayGateway?: string
|
|
360
|
+
googlePayGatewayMerchantId?: string
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Returns
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
interface UsePaymentCheckoutReturn {
|
|
368
|
+
// Payment availability
|
|
369
|
+
canMakePayments: boolean // Can user make payments?
|
|
370
|
+
canSetupCards: boolean // Can user add cards?
|
|
371
|
+
isCheckingStatus: boolean // Loading state for availability check
|
|
372
|
+
|
|
373
|
+
// Cart management
|
|
374
|
+
items: PaymentItem[] // Current cart items
|
|
375
|
+
total: number // Total amount
|
|
376
|
+
addItem: (label: string, amount: number, type?: 'final' | 'pending') => void
|
|
377
|
+
addItems: (items: Array<{ label; amount; type? }>) => void
|
|
378
|
+
removeItem: (index: number) => void
|
|
379
|
+
updateItem: (index: number, updates: Partial<PaymentItem>) => void
|
|
380
|
+
clearItems: () => void
|
|
381
|
+
|
|
382
|
+
// Payment processing
|
|
383
|
+
startPayment: () => Promise<PaymentResult | null>
|
|
384
|
+
isProcessing: boolean // Payment in progress?
|
|
385
|
+
result: PaymentResult | null // Last payment result
|
|
386
|
+
error: Error | null // Last error
|
|
387
|
+
|
|
388
|
+
// Utilities
|
|
389
|
+
reset: () => void // Reset payment state
|
|
390
|
+
paymentRequest: PaymentRequest // Full request object
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
#### Example
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
const checkout = usePaymentCheckout({
|
|
398
|
+
merchantIdentifier: 'merchant.com.example',
|
|
399
|
+
currencyCode: 'USD',
|
|
400
|
+
countryCode: 'US',
|
|
401
|
+
googlePayEnvironment: 'TEST',
|
|
402
|
+
googlePayGateway: 'stripe',
|
|
403
|
+
googlePayGatewayMerchantId: 'your_stripe_merchant_id',
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
// Add single item
|
|
407
|
+
checkout.addItem('Product', 29.99)
|
|
408
|
+
|
|
409
|
+
// Add multiple items at once
|
|
410
|
+
checkout.addItems([
|
|
411
|
+
{ label: 'Product', amount: 29.99 },
|
|
412
|
+
{ label: 'Shipping', amount: 5.0 },
|
|
413
|
+
{ label: 'Tax', amount: 2.8, type: 'final' },
|
|
414
|
+
])
|
|
415
|
+
|
|
416
|
+
// Process payment
|
|
417
|
+
const result = await checkout.startPayment()
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
### `HybridPaymentHandler`
|
|
423
|
+
|
|
424
|
+
Low-level payment handler for direct control.
|
|
425
|
+
|
|
426
|
+
#### Methods
|
|
427
|
+
|
|
428
|
+
##### `payServiceStatus(): PayServiceStatus`
|
|
429
|
+
|
|
430
|
+
Check payment service availability.
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
const status = HybridPaymentHandler.payServiceStatus()
|
|
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
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
##### `startPayment(request: PaymentRequest): Promise<PaymentResult>`
|
|
448
|
+
|
|
449
|
+
Start a payment request.
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
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
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
##### `canMakePayments(usingNetworks: string[]): boolean`
|
|
480
|
+
|
|
481
|
+
Check if specific card networks are supported.
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
const canPay = HybridPaymentHandler.canMakePayments(['visa', 'mastercard'])
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
### Button Components
|
|
490
|
+
|
|
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
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
<ApplePayButton
|
|
528
|
+
buttonType="buy"
|
|
529
|
+
buttonStyle="black"
|
|
530
|
+
onPress={handlePayment}
|
|
531
|
+
style={{ width: '100%', height: 48 }}
|
|
532
|
+
/>
|
|
533
|
+
```
|
|
534
|
+
|
|
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
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
<GooglePayButton
|
|
566
|
+
buttonType="buy"
|
|
567
|
+
theme="dark"
|
|
568
|
+
radius={8}
|
|
569
|
+
onPress={handlePayment}
|
|
570
|
+
style={{ width: '100%', height: 48 }}
|
|
571
|
+
/>
|
|
572
|
+
```
|
|
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
|
+
|
|
911
|
+
## Architecture
|
|
912
|
+
|
|
913
|
+
### Package Structure
|
|
914
|
+
|
|
915
|
+
```
|
|
916
|
+
@gmisoftware/react-native-pay/
|
|
917
|
+
├── android/ # Android implementation
|
|
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
|
+
│
|
|
928
|
+
├── ios/ # iOS implementation
|
|
929
|
+
│ ├── ApplePayButtonFactory.swift # Button factory
|
|
930
|
+
│ ├── HybridApplePayButton.swift # Button component
|
|
931
|
+
│ ├── HybridPaymentHandler.swift # Payment handler
|
|
932
|
+
│ └── PassKitTypeMapper.swift # Type conversion
|
|
933
|
+
│
|
|
934
|
+
├── src/ # TypeScript source
|
|
935
|
+
│ ├── specs/ # Nitro specifications
|
|
936
|
+
│ │ ├── ApplePayButton.nitro.ts
|
|
937
|
+
│ │ ├── GooglePayButton.nitro.ts
|
|
938
|
+
│ │ └── PaymentHandler.nitro.ts
|
|
939
|
+
│ ├── types/ # Type definitions
|
|
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
|
|
949
|
+
│ ├── plugin/ # Expo config plugins
|
|
950
|
+
│ │ ├── withApplePay.ts
|
|
951
|
+
│ │ ├── withGooglePay.ts
|
|
952
|
+
│ │ └── index.ts
|
|
953
|
+
│ └── index.ts # Public API
|
|
954
|
+
│
|
|
955
|
+
├── nitrogen/ # Generated code
|
|
956
|
+
│ └── generated/
|
|
957
|
+
│ ├── android/
|
|
958
|
+
│ ├── ios/
|
|
959
|
+
│ └── shared/
|
|
960
|
+
│
|
|
961
|
+
└── package.json
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
### Design Principles
|
|
965
|
+
|
|
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
|
+
---
|
|
1050
|
+
|
|
1051
|
+
## Contributing
|
|
1052
|
+
|
|
1053
|
+
We welcome contributions! Please follow these guidelines:
|
|
1054
|
+
|
|
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
|
+
---
|
|
1104
|
+
|
|
1105
|
+
## License
|
|
1106
|
+
|
|
1107
|
+
MIT © [GMI Software](https://gmi.software)
|
|
1108
|
+
|
|
1109
|
+
---
|
|
1110
|
+
|
|
1111
|
+
## Credits
|
|
1112
|
+
|
|
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.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"author": "gmi.software",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -8,9 +8,6 @@
|
|
|
8
8
|
},
|
|
9
9
|
"main": "lib/index",
|
|
10
10
|
"module": "lib/index",
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"expo": "^53.0.0"
|
|
13
|
-
},
|
|
14
11
|
"devDependencies": {
|
|
15
12
|
"@react-native/eslint-config": "0.82.0",
|
|
16
13
|
"@types/jest": "^29.5.12",
|
|
@@ -20,7 +17,8 @@
|
|
|
20
17
|
"eslint-plugin-prettier": "^5.2.1",
|
|
21
18
|
"nitrogen": "*",
|
|
22
19
|
"prettier": "^3.3.3",
|
|
23
|
-
"typescript": "^5.8.3"
|
|
20
|
+
"typescript": "^5.8.3",
|
|
21
|
+
"release-it": "^19.0.0"
|
|
24
22
|
},
|
|
25
23
|
"peerDependencies": {
|
|
26
24
|
"react": "*",
|
|
@@ -103,14 +101,17 @@
|
|
|
103
101
|
},
|
|
104
102
|
"react-native": "src/index",
|
|
105
103
|
"scripts": {
|
|
104
|
+
"prepack": "cp ../README.md ./README.md",
|
|
105
|
+
"postpack": "rm ./README.md",
|
|
106
106
|
"postinstall": "tsc || exit 0;",
|
|
107
107
|
"typecheck": "tsc --noEmit",
|
|
108
108
|
"clean": "rm -rf android/build node_modules/**/android/build lib",
|
|
109
109
|
"lint": "eslint \"**/*.{js,ts,tsx}\" --fix",
|
|
110
110
|
"lint-ci": "eslint \"**/*.{js,ts,tsx}\" -f @jamesacarr/github-actions",
|
|
111
111
|
"typescript": "tsc",
|
|
112
|
-
"specs": "typescript && nitrogen --logLevel=\"debug\""
|
|
112
|
+
"specs": "typescript && nitrogen --logLevel=\"debug\"",
|
|
113
|
+
"release": "release-it"
|
|
113
114
|
},
|
|
114
115
|
"source": "src/index",
|
|
115
116
|
"types": "lib/index.d.ts"
|
|
116
|
-
}
|
|
117
|
+
}
|