@payment-kit-js/vanilla 0.1.0-alpha.0
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 +755 -0
- package/dist/cardsetupintent-D2gBMj3e.d.mts +35 -0
- package/dist/cardsetupintent-D2gBMj3e.d.mts.map +1 -0
- package/dist/connect-card-DO2EJxu6.mjs +19 -0
- package/dist/connect-card-DO2EJxu6.mjs.map +1 -0
- package/dist/connect-card-EaOlRbPS.d.mts +25 -0
- package/dist/connect-card-EaOlRbPS.d.mts.map +1 -0
- package/dist/connect-tunnel-x-BhVAej5Q.mjs +44 -0
- package/dist/connect-tunnel-x-BhVAej5Q.mjs.map +1 -0
- package/dist/connect-tunnel-x-Ce423Pa2.d.mts +92 -0
- package/dist/connect-tunnel-x-Ce423Pa2.d.mts.map +1 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +69 -0
- package/dist/index.mjs.map +1 -0
- package/dist/next-action-handlers-DTsWjUIA.mjs +53 -0
- package/dist/next-action-handlers-DTsWjUIA.mjs.map +1 -0
- package/dist/payment-methods/card.d.mts +22 -0
- package/dist/payment-methods/card.d.mts.map +1 -0
- package/dist/payment-methods/card.mjs +183 -0
- package/dist/payment-methods/card.mjs.map +1 -0
- package/dist/payment-methods/google-pay.d.mts +49 -0
- package/dist/payment-methods/google-pay.d.mts.map +1 -0
- package/dist/payment-methods/google-pay.mjs +135 -0
- package/dist/payment-methods/google-pay.mjs.map +1 -0
- package/dist/payment-methods/next-action-handlers.d.mts +24 -0
- package/dist/payment-methods/next-action-handlers.d.mts.map +1 -0
- package/dist/payment-methods/next-action-handlers.mjs +3 -0
- package/dist/payment-methods/paypal.d.mts +49 -0
- package/dist/payment-methods/paypal.d.mts.map +1 -0
- package/dist/payment-methods/paypal.mjs +93 -0
- package/dist/payment-methods/paypal.mjs.map +1 -0
- package/dist/payment-methods/stripe-google-pay-adapter.d.mts +2 -0
- package/dist/payment-methods/stripe-google-pay-adapter.mjs +3 -0
- package/dist/penpal/connect-card.d.mts +4 -0
- package/dist/penpal/connect-card.mjs +4 -0
- package/dist/penpal/connect-tunnel-x.d.mts +3 -0
- package/dist/penpal/connect-tunnel-x.mjs +4 -0
- package/dist/penpal-BFKeZTVz.mjs +16 -0
- package/dist/penpal-BFKeZTVz.mjs.map +1 -0
- package/dist/publiccardcheckoutresponse-wxFCeVdO.d.mts +40 -0
- package/dist/publiccardcheckoutresponse-wxFCeVdO.d.mts.map +1 -0
- package/dist/stripe-google-pay-adapter-CkV5HWI-.d.mts +54 -0
- package/dist/stripe-google-pay-adapter-CkV5HWI-.d.mts.map +1 -0
- package/dist/stripe-google-pay-adapter-DMDArVp2.mjs +163 -0
- package/dist/stripe-google-pay-adapter-DMDArVp2.mjs.map +1 -0
- package/dist/types-6mOKdjCh.d.mts +64 -0
- package/dist/types-6mOKdjCh.d.mts.map +1 -0
- package/dist/utils-h0dxplHy.mjs +62 -0
- package/dist/utils-h0dxplHy.mjs.map +1 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,755 @@
|
|
|
1
|
+
# @payment-kit-js/vanilla
|
|
2
|
+
|
|
3
|
+
Vanilla JavaScript SDK for PaymentKit - A type-safe, framework-agnostic payment processing SDK supporting card payments, PayPal, and Google Pay.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @payment-kit-js/vanilla
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import PaymentKit from '@payment-kit-js/vanilla';
|
|
15
|
+
import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card';
|
|
16
|
+
|
|
17
|
+
// Initialize PaymentKit
|
|
18
|
+
const paymentKit = PaymentKit({
|
|
19
|
+
baseUrl: 'https://your-domain.com', // For loading iframes
|
|
20
|
+
apiBaseUrl: 'https://api.domain.com', // For API calls (optional, defaults to baseUrl)
|
|
21
|
+
secureToken: 'checkout_session_token', // From your backend
|
|
22
|
+
paymentMethods: [CardPaymentMethod]
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Mount card inputs
|
|
26
|
+
paymentKit.card.createElement('card_pan').mount('#card-number');
|
|
27
|
+
paymentKit.card.createElement('card_exp').mount('#card-expiry');
|
|
28
|
+
paymentKit.card.createElement('card_cvc').mount('#card-cvc');
|
|
29
|
+
|
|
30
|
+
// Submit payment
|
|
31
|
+
paymentKit.submit({
|
|
32
|
+
fields: {
|
|
33
|
+
customer_name: 'John Doe',
|
|
34
|
+
customer_email: 'john@example.com',
|
|
35
|
+
customer_country: 'US',
|
|
36
|
+
customer_zip_code: '10001'
|
|
37
|
+
},
|
|
38
|
+
paymentMethod: 'card',
|
|
39
|
+
onSuccess: (result) => console.log('Success:', result),
|
|
40
|
+
onError: (errors) => console.error('Error:', errors)
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Cleanup when done
|
|
44
|
+
paymentKit.cleanup();
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Payment Methods
|
|
48
|
+
|
|
49
|
+
### Card Payments
|
|
50
|
+
|
|
51
|
+
Secure PCI-compliant card payments using isolated iframes.
|
|
52
|
+
|
|
53
|
+
#### Import
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card';
|
|
57
|
+
import type { CardInputType } from '@payment-kit-js/vanilla/payment-methods/card';
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### Initialize
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const paymentKit = PaymentKit({
|
|
64
|
+
baseUrl: 'https://your-domain.com',
|
|
65
|
+
secureToken: 'checkout_token',
|
|
66
|
+
paymentMethods: [CardPaymentMethod]
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### Create Card Elements
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
// Card input types: 'card_pan' | 'card_exp' | 'card_cvc'
|
|
74
|
+
const cardNumber = paymentKit.card.createElement('card_pan', {
|
|
75
|
+
style: {
|
|
76
|
+
height: '40px',
|
|
77
|
+
fontSize: '16px',
|
|
78
|
+
fontFamily: 'Arial, sans-serif',
|
|
79
|
+
color: '#32325d',
|
|
80
|
+
padding: '10px'
|
|
81
|
+
},
|
|
82
|
+
onLoaded: () => console.log('Card input loaded'),
|
|
83
|
+
onFocusChange: (isFocused) => console.log('Focus:', isFocused)
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Mount to DOM
|
|
87
|
+
const { unmount } = cardNumber.mount('#card-number-container');
|
|
88
|
+
|
|
89
|
+
// Unmount when needed
|
|
90
|
+
unmount();
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Submit Card Payment
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
paymentKit.submit({
|
|
97
|
+
fields: {
|
|
98
|
+
customer_name: 'John Doe',
|
|
99
|
+
customer_email: 'john@example.com',
|
|
100
|
+
customer_country: 'US',
|
|
101
|
+
customer_zip_code: '10001'
|
|
102
|
+
},
|
|
103
|
+
paymentMethod: 'card',
|
|
104
|
+
onSuccess: (result) => {
|
|
105
|
+
// result: { id, checkoutAttemptId, checkoutSessionId, paymentIntentId, state }
|
|
106
|
+
console.log('Payment successful:', result);
|
|
107
|
+
},
|
|
108
|
+
onError: (errors) => {
|
|
109
|
+
// errors.card_pan, errors.card_exp, errors.card_cvc
|
|
110
|
+
// errors.customer_name, errors.customer_email, etc.
|
|
111
|
+
console.error('Payment failed:', errors);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### 3D Secure (3DS) Support
|
|
117
|
+
|
|
118
|
+
Card payments automatically handle 3D Secure authentication:
|
|
119
|
+
|
|
120
|
+
1. Submit payment
|
|
121
|
+
2. If 3DS required, user is redirected to bank authentication page
|
|
122
|
+
3. After authentication, payment completes automatically
|
|
123
|
+
4. Success/error callback is triggered
|
|
124
|
+
|
|
125
|
+
No additional code needed - it's built-in!
|
|
126
|
+
|
|
127
|
+
### PayPal
|
|
128
|
+
|
|
129
|
+
PayPal payments using popup-based authentication flow.
|
|
130
|
+
|
|
131
|
+
#### Import
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import PayPalPaymentMethod from '@payment-kit-js/vanilla/payment-methods/paypal';
|
|
135
|
+
import type { PayPalSubmitOptions } from '@payment-kit-js/vanilla/payment-methods/paypal';
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Initialize
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
const paymentKit = PaymentKit({
|
|
142
|
+
baseUrl: 'https://your-domain.com',
|
|
143
|
+
apiBaseUrl: 'https://api.domain.com',
|
|
144
|
+
secureToken: 'checkout_token',
|
|
145
|
+
paymentMethods: [PayPalPaymentMethod]
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Submit PayPal Payment
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
paymentKit.submit({
|
|
153
|
+
fields: {
|
|
154
|
+
customer_name: 'John Doe',
|
|
155
|
+
customer_email: 'john@example.com',
|
|
156
|
+
customer_country: 'US',
|
|
157
|
+
customer_zip_code: '10001'
|
|
158
|
+
},
|
|
159
|
+
paymentMethod: 'paypal',
|
|
160
|
+
options: {
|
|
161
|
+
processorId: 'proc_xxx', // Your PayPal processor ID
|
|
162
|
+
customerInfo: {
|
|
163
|
+
first_name: 'John',
|
|
164
|
+
last_name: 'Doe'
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
onSuccess: (result) => {
|
|
168
|
+
console.log('PayPal payment approved:', result);
|
|
169
|
+
},
|
|
170
|
+
onError: (errors) => {
|
|
171
|
+
if (errors.paypal?.includes('popup')) {
|
|
172
|
+
alert('Please allow popups for PayPal payments');
|
|
173
|
+
}
|
|
174
|
+
console.error('PayPal error:', errors);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Important**: PayPal requires browser popups to be enabled. The SDK automatically:
|
|
180
|
+
- Opens PayPal authentication popup
|
|
181
|
+
- Polls for payment completion every 2 seconds
|
|
182
|
+
- Closes popup after completion
|
|
183
|
+
- Handles user cancellation
|
|
184
|
+
|
|
185
|
+
### Google Pay
|
|
186
|
+
|
|
187
|
+
Google Pay payments using Stripe Payment Request API.
|
|
188
|
+
|
|
189
|
+
#### Import
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import GooglePayPaymentMethod from '@payment-kit-js/vanilla/payment-methods/google-pay';
|
|
193
|
+
import type { GooglePaySubmitOptions } from '@payment-kit-js/vanilla/payment-methods/google-pay';
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### Prerequisites
|
|
197
|
+
|
|
198
|
+
Add Stripe.js to your HTML:
|
|
199
|
+
|
|
200
|
+
```html
|
|
201
|
+
<script src="https://js.stripe.com/v3/"></script>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### Initialize
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
const paymentKit = PaymentKit({
|
|
208
|
+
baseUrl: 'https://your-domain.com',
|
|
209
|
+
apiBaseUrl: 'https://api.domain.com',
|
|
210
|
+
secureToken: 'checkout_token',
|
|
211
|
+
paymentMethods: [GooglePayPaymentMethod]
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### Submit Google Pay Payment
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
paymentKit.submit({
|
|
219
|
+
fields: {
|
|
220
|
+
customer_name: 'John Doe',
|
|
221
|
+
customer_email: 'john@example.com',
|
|
222
|
+
customer_country: 'US',
|
|
223
|
+
customer_zip_code: '10001'
|
|
224
|
+
},
|
|
225
|
+
paymentMethod: 'google_pay',
|
|
226
|
+
options: {
|
|
227
|
+
processorId: 'proc_xxx', // Your Google Pay processor ID
|
|
228
|
+
customerInfo: {
|
|
229
|
+
first_name: 'John',
|
|
230
|
+
last_name: 'Doe'
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
onSuccess: (result) => {
|
|
234
|
+
console.log('Google Pay success:', result);
|
|
235
|
+
},
|
|
236
|
+
onError: (errors) => {
|
|
237
|
+
if (errors.google_pay === 'Google Pay not available on this device') {
|
|
238
|
+
// Show alternative payment methods
|
|
239
|
+
}
|
|
240
|
+
console.error('Google Pay error:', errors);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Multiple Payment Methods
|
|
246
|
+
|
|
247
|
+
Enable multiple payment methods in a single instance:
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card';
|
|
251
|
+
import PayPalPaymentMethod from '@payment-kit-js/vanilla/payment-methods/paypal';
|
|
252
|
+
import GooglePayPaymentMethod from '@payment-kit-js/vanilla/payment-methods/google-pay';
|
|
253
|
+
|
|
254
|
+
const paymentKit = PaymentKit({
|
|
255
|
+
baseUrl: 'https://your-domain.com',
|
|
256
|
+
apiBaseUrl: 'https://api.domain.com',
|
|
257
|
+
secureToken: 'checkout_token',
|
|
258
|
+
paymentMethods: [CardPaymentMethod, PayPalPaymentMethod, GooglePayPaymentMethod]
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// TypeScript knows all available methods
|
|
262
|
+
paymentKit.card.createElement('card_pan'); // ✓
|
|
263
|
+
paymentKit.submit({ paymentMethod: 'card', ... }); // ✓
|
|
264
|
+
paymentKit.submit({ paymentMethod: 'paypal', ... }); // ✓
|
|
265
|
+
paymentKit.submit({ paymentMethod: 'google_pay', ... }); // ✓
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## API Reference
|
|
269
|
+
|
|
270
|
+
### `PaymentKit(config)`
|
|
271
|
+
|
|
272
|
+
Initialize PaymentKit instance.
|
|
273
|
+
|
|
274
|
+
**Parameters**:
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
{
|
|
278
|
+
baseUrl: string; // URL for loading iframes (e.g., https://your-domain.com)
|
|
279
|
+
apiBaseUrl?: string; // URL for API calls (defaults to baseUrl)
|
|
280
|
+
secureToken: string; // Checkout session token from your backend
|
|
281
|
+
paymentMethods: PaymentMethod[]; // Array of payment method handlers
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**Returns**: Object with payment method APIs + `submit()` + `cleanup()`
|
|
286
|
+
|
|
287
|
+
### `submit(options)`
|
|
288
|
+
|
|
289
|
+
Submit a payment using specified payment method.
|
|
290
|
+
|
|
291
|
+
**Parameters**:
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
{
|
|
295
|
+
fields: {
|
|
296
|
+
customer_name: string;
|
|
297
|
+
customer_email: string;
|
|
298
|
+
customer_country: string;
|
|
299
|
+
customer_zip_code: string;
|
|
300
|
+
};
|
|
301
|
+
paymentMethod: 'card' | 'paypal' | 'google_pay';
|
|
302
|
+
options?: unknown; // Payment method specific options
|
|
303
|
+
onSuccess: (result: { [key: string]: unknown }) => void;
|
|
304
|
+
onError: (errors: PaymentKitErrors) => void;
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### `cleanup()`
|
|
309
|
+
|
|
310
|
+
Clean up all resources (iframes, popups, connections). **Always call this** when unmounting or leaving checkout.
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
useEffect(() => {
|
|
314
|
+
return () => {
|
|
315
|
+
paymentKit.cleanup();
|
|
316
|
+
};
|
|
317
|
+
}, [paymentKit]);
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Card API
|
|
321
|
+
|
|
322
|
+
#### `card.createElement(type, options)`
|
|
323
|
+
|
|
324
|
+
Create a secure card input iframe.
|
|
325
|
+
|
|
326
|
+
**Types**:
|
|
327
|
+
- `'card_pan'` - Card number
|
|
328
|
+
- `'card_exp'` - Expiration (MM/YY)
|
|
329
|
+
- `'card_cvc'` - Security code
|
|
330
|
+
|
|
331
|
+
**Options**:
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
{
|
|
335
|
+
style?: Record<string, string>; // CSS properties
|
|
336
|
+
onLoaded?: () => void;
|
|
337
|
+
onFocusChange?: (isFocused: boolean) => void;
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Returns**: `{ mount: (selector: string) => { unmount: () => void } }`
|
|
342
|
+
|
|
343
|
+
## Types
|
|
344
|
+
|
|
345
|
+
### PaymentKitFields
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
type PaymentKitFields = {
|
|
349
|
+
customer_name: string;
|
|
350
|
+
customer_email: string;
|
|
351
|
+
customer_country: string;
|
|
352
|
+
customer_zip_code: string;
|
|
353
|
+
};
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### PaymentKitErrors
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
type PaymentKitErrors = {
|
|
360
|
+
root?: string;
|
|
361
|
+
|
|
362
|
+
// Card errors
|
|
363
|
+
card_pan?: CardErrorCode;
|
|
364
|
+
card_exp?: CardErrorCode;
|
|
365
|
+
card_cvc?: CardErrorCode;
|
|
366
|
+
|
|
367
|
+
// PayPal errors
|
|
368
|
+
paypal?: string;
|
|
369
|
+
|
|
370
|
+
// Google Pay errors
|
|
371
|
+
google_pay?: string;
|
|
372
|
+
|
|
373
|
+
// Field validation
|
|
374
|
+
customer_name?: 'required' | 'invalid';
|
|
375
|
+
customer_email?: 'required' | 'invalid';
|
|
376
|
+
customer_country?: 'required' | 'invalid';
|
|
377
|
+
customer_zip_code?: 'required' | 'invalid';
|
|
378
|
+
|
|
379
|
+
// Processor
|
|
380
|
+
processor_id?: string;
|
|
381
|
+
};
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### CardErrorCode
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
type CardErrorCode =
|
|
388
|
+
| 'required'
|
|
389
|
+
| 'invalid'
|
|
390
|
+
| 'incomplete'
|
|
391
|
+
| 'invalid_number'
|
|
392
|
+
| 'invalid_expiry'
|
|
393
|
+
| 'invalid_cvc';
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## React Example
|
|
397
|
+
|
|
398
|
+
### PaymentKit Provider
|
|
399
|
+
|
|
400
|
+
```tsx
|
|
401
|
+
import { createContext, useContext, useEffect, useState } from 'react';
|
|
402
|
+
import PaymentKit from '@payment-kit-js/vanilla';
|
|
403
|
+
import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card';
|
|
404
|
+
import PayPalPaymentMethod from '@payment-kit-js/vanilla/payment-methods/paypal';
|
|
405
|
+
import GooglePayPaymentMethod from '@payment-kit-js/vanilla/payment-methods/google-pay';
|
|
406
|
+
|
|
407
|
+
type PaymentKitInstance = ReturnType<typeof PaymentKit<
|
|
408
|
+
[typeof CardPaymentMethod, typeof PayPalPaymentMethod, typeof GooglePayPaymentMethod]
|
|
409
|
+
>>;
|
|
410
|
+
|
|
411
|
+
const PaymentKitContext = createContext<PaymentKitInstance | null>(null);
|
|
412
|
+
|
|
413
|
+
export const usePaymentKit = () => {
|
|
414
|
+
const pk = useContext(PaymentKitContext);
|
|
415
|
+
if (!pk) throw new Error('PaymentKit not initialized');
|
|
416
|
+
return pk;
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
export const PaymentKitProvider = ({
|
|
420
|
+
children,
|
|
421
|
+
secureToken
|
|
422
|
+
}: {
|
|
423
|
+
children: React.ReactNode;
|
|
424
|
+
secureToken: string;
|
|
425
|
+
}) => {
|
|
426
|
+
const [paymentKit, setPaymentKit] = useState<PaymentKitInstance | null>(null);
|
|
427
|
+
|
|
428
|
+
useEffect(() => {
|
|
429
|
+
const pk = PaymentKit({
|
|
430
|
+
baseUrl: 'https://your-domain.com',
|
|
431
|
+
apiBaseUrl: 'https://api.domain.com',
|
|
432
|
+
secureToken,
|
|
433
|
+
paymentMethods: [CardPaymentMethod, PayPalPaymentMethod, GooglePayPaymentMethod]
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
setPaymentKit(pk);
|
|
437
|
+
return () => pk.cleanup();
|
|
438
|
+
}, [secureToken]);
|
|
439
|
+
|
|
440
|
+
if (!paymentKit) return null;
|
|
441
|
+
|
|
442
|
+
return (
|
|
443
|
+
<PaymentKitContext.Provider value={paymentKit}>
|
|
444
|
+
{children}
|
|
445
|
+
</PaymentKitContext.Provider>
|
|
446
|
+
);
|
|
447
|
+
};
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Card Input Component
|
|
451
|
+
|
|
452
|
+
```tsx
|
|
453
|
+
import { useEffect } from 'react';
|
|
454
|
+
import { usePaymentKit } from './PaymentKitProvider';
|
|
455
|
+
import type { CardInputType } from '@payment-kit-js/vanilla/payment-methods/card';
|
|
456
|
+
|
|
457
|
+
export const CardInput = ({
|
|
458
|
+
type,
|
|
459
|
+
className
|
|
460
|
+
}: {
|
|
461
|
+
type: CardInputType;
|
|
462
|
+
className?: string;
|
|
463
|
+
}) => {
|
|
464
|
+
const paymentKit = usePaymentKit();
|
|
465
|
+
|
|
466
|
+
useEffect(() => {
|
|
467
|
+
const element = paymentKit.card.createElement(type, {
|
|
468
|
+
style: {
|
|
469
|
+
height: '42px',
|
|
470
|
+
fontSize: '16px',
|
|
471
|
+
padding: '10px',
|
|
472
|
+
border: '1px solid #e0e0e0',
|
|
473
|
+
borderRadius: '4px'
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
const { unmount } = element.mount(`#${type}`);
|
|
478
|
+
return unmount;
|
|
479
|
+
}, [type, paymentKit]);
|
|
480
|
+
|
|
481
|
+
return <div id={type} className={className} />;
|
|
482
|
+
};
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Payment Form
|
|
486
|
+
|
|
487
|
+
```tsx
|
|
488
|
+
import { useState } from 'react';
|
|
489
|
+
import { usePaymentKit } from './PaymentKitProvider';
|
|
490
|
+
import { CardInput } from './CardInput';
|
|
491
|
+
|
|
492
|
+
export const PaymentForm = () => {
|
|
493
|
+
const paymentKit = usePaymentKit();
|
|
494
|
+
const [loading, setLoading] = useState(false);
|
|
495
|
+
const [values, setValues] = useState({
|
|
496
|
+
customer_name: '',
|
|
497
|
+
customer_email: '',
|
|
498
|
+
customer_country: '',
|
|
499
|
+
customer_zip_code: ''
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
const handleCardPayment = () => {
|
|
503
|
+
setLoading(true);
|
|
504
|
+
paymentKit.submit({
|
|
505
|
+
fields: values,
|
|
506
|
+
paymentMethod: 'card',
|
|
507
|
+
onSuccess: (result) => {
|
|
508
|
+
setLoading(false);
|
|
509
|
+
console.log('Success:', result);
|
|
510
|
+
},
|
|
511
|
+
onError: (errors) => {
|
|
512
|
+
setLoading(false);
|
|
513
|
+
console.error('Error:', errors);
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
const handlePayPalPayment = () => {
|
|
519
|
+
const [firstName, ...rest] = values.customer_name.split(' ');
|
|
520
|
+
setLoading(true);
|
|
521
|
+
|
|
522
|
+
paymentKit.submit({
|
|
523
|
+
fields: values,
|
|
524
|
+
paymentMethod: 'paypal',
|
|
525
|
+
options: {
|
|
526
|
+
processorId: 'proc_xxx',
|
|
527
|
+
customerInfo: {
|
|
528
|
+
first_name: firstName,
|
|
529
|
+
last_name: rest.join(' ')
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
onSuccess: (result) => {
|
|
533
|
+
setLoading(false);
|
|
534
|
+
console.log('PayPal success:', result);
|
|
535
|
+
},
|
|
536
|
+
onError: (errors) => {
|
|
537
|
+
setLoading(false);
|
|
538
|
+
console.error('PayPal error:', errors);
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
const handleGooglePayment = () => {
|
|
544
|
+
const [firstName, ...rest] = values.customer_name.split(' ');
|
|
545
|
+
setLoading(true);
|
|
546
|
+
|
|
547
|
+
paymentKit.submit({
|
|
548
|
+
fields: values,
|
|
549
|
+
paymentMethod: 'google_pay',
|
|
550
|
+
options: {
|
|
551
|
+
processorId: 'proc_xxx',
|
|
552
|
+
customerInfo: {
|
|
553
|
+
first_name: firstName,
|
|
554
|
+
last_name: rest.join(' ')
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
onSuccess: (result) => {
|
|
558
|
+
setLoading(false);
|
|
559
|
+
console.log('Google Pay success:', result);
|
|
560
|
+
},
|
|
561
|
+
onError: (errors) => {
|
|
562
|
+
setLoading(false);
|
|
563
|
+
console.error('Google Pay error:', errors);
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
return (
|
|
569
|
+
<form onSubmit={(e) => e.preventDefault()}>
|
|
570
|
+
<input
|
|
571
|
+
placeholder="Name"
|
|
572
|
+
value={values.customer_name}
|
|
573
|
+
onChange={(e) => setValues(prev => ({ ...prev, customer_name: e.target.value }))}
|
|
574
|
+
/>
|
|
575
|
+
<input
|
|
576
|
+
placeholder="Email"
|
|
577
|
+
value={values.customer_email}
|
|
578
|
+
onChange={(e) => setValues(prev => ({ ...prev, customer_email: e.target.value }))}
|
|
579
|
+
/>
|
|
580
|
+
<input
|
|
581
|
+
placeholder="Country"
|
|
582
|
+
value={values.customer_country}
|
|
583
|
+
onChange={(e) => setValues(prev => ({ ...prev, customer_country: e.target.value }))}
|
|
584
|
+
/>
|
|
585
|
+
<input
|
|
586
|
+
placeholder="Zip Code"
|
|
587
|
+
value={values.customer_zip_code}
|
|
588
|
+
onChange={(e) => setValues(prev => ({ ...prev, customer_zip_code: e.target.value }))}
|
|
589
|
+
/>
|
|
590
|
+
|
|
591
|
+
<h3>Card Payment</h3>
|
|
592
|
+
<CardInput type="card_pan" />
|
|
593
|
+
<CardInput type="card_exp" />
|
|
594
|
+
<CardInput type="card_cvc" />
|
|
595
|
+
<button onClick={handleCardPayment} disabled={loading}>
|
|
596
|
+
Pay with Card
|
|
597
|
+
</button>
|
|
598
|
+
|
|
599
|
+
<h3>Alternative Payments</h3>
|
|
600
|
+
<button onClick={handlePayPalPayment} disabled={loading}>
|
|
601
|
+
Pay with PayPal
|
|
602
|
+
</button>
|
|
603
|
+
<button onClick={handleGooglePayment} disabled={loading}>
|
|
604
|
+
Pay with Google Pay
|
|
605
|
+
</button>
|
|
606
|
+
</form>
|
|
607
|
+
);
|
|
608
|
+
};
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
## Error Handling
|
|
612
|
+
|
|
613
|
+
### Validation Errors
|
|
614
|
+
|
|
615
|
+
```typescript
|
|
616
|
+
paymentKit.submit({
|
|
617
|
+
fields: values,
|
|
618
|
+
paymentMethod: 'card',
|
|
619
|
+
onError: (errors) => {
|
|
620
|
+
if (errors.customer_email === 'required') {
|
|
621
|
+
showError('Email is required');
|
|
622
|
+
}
|
|
623
|
+
if (errors.card_pan === 'invalid_number') {
|
|
624
|
+
showError('Invalid card number');
|
|
625
|
+
}
|
|
626
|
+
},
|
|
627
|
+
onSuccess: () => { /* ... */ }
|
|
628
|
+
});
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### Payment Method Specific Errors
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
// Card errors
|
|
635
|
+
onError: (errors) => {
|
|
636
|
+
if (errors.card_pan) console.error('Card number error');
|
|
637
|
+
if (errors.card_exp) console.error('Expiry error');
|
|
638
|
+
if (errors.card_cvc) console.error('CVC error');
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// PayPal errors
|
|
642
|
+
onError: (errors) => {
|
|
643
|
+
if (errors.paypal?.includes('popup')) {
|
|
644
|
+
alert('Please enable popups');
|
|
645
|
+
}
|
|
646
|
+
if (errors.paypal?.includes('cancelled')) {
|
|
647
|
+
console.log('User cancelled PayPal');
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// Google Pay errors
|
|
652
|
+
onError: (errors) => {
|
|
653
|
+
if (errors.google_pay === 'Google Pay not available on this device') {
|
|
654
|
+
// Hide Google Pay button
|
|
655
|
+
}
|
|
656
|
+
if (errors.google_pay?.includes('cancelled')) {
|
|
657
|
+
console.log('User cancelled Google Pay');
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
## Best Practices
|
|
663
|
+
|
|
664
|
+
### 1. Always Cleanup
|
|
665
|
+
|
|
666
|
+
```typescript
|
|
667
|
+
useEffect(() => {
|
|
668
|
+
const pk = PaymentKit({ /* config */ });
|
|
669
|
+
return () => pk.cleanup(); // Critical!
|
|
670
|
+
}, []);
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
### 2. Handle Loading States
|
|
674
|
+
|
|
675
|
+
```typescript
|
|
676
|
+
const [loading, setLoading] = useState(false);
|
|
677
|
+
|
|
678
|
+
const handleSubmit = () => {
|
|
679
|
+
setLoading(true);
|
|
680
|
+
paymentKit.submit({
|
|
681
|
+
// ...
|
|
682
|
+
onSuccess: () => setLoading(false),
|
|
683
|
+
onError: () => setLoading(false)
|
|
684
|
+
});
|
|
685
|
+
};
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### 3. Validate Before Submit
|
|
689
|
+
|
|
690
|
+
```typescript
|
|
691
|
+
const handleSubmit = () => {
|
|
692
|
+
if (!values.customer_email || !values.customer_name) {
|
|
693
|
+
setError('Please fill required fields');
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
paymentKit.submit({ /* ... */ });
|
|
697
|
+
};
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### 4. Provide Fallback for Unsupported Methods
|
|
701
|
+
|
|
702
|
+
```typescript
|
|
703
|
+
// Check Google Pay availability
|
|
704
|
+
paymentKit.submit({
|
|
705
|
+
paymentMethod: 'google_pay',
|
|
706
|
+
onError: (errors) => {
|
|
707
|
+
if (errors.google_pay?.includes('not available')) {
|
|
708
|
+
setShowGooglePay(false); // Hide button
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### 5. Type Safety with TypeScript
|
|
715
|
+
|
|
716
|
+
```typescript
|
|
717
|
+
// Type the instance based on enabled payment methods
|
|
718
|
+
type PaymentKitInstance = ReturnType<typeof PaymentKit<
|
|
719
|
+
[typeof CardPaymentMethod, typeof PayPalPaymentMethod]
|
|
720
|
+
>>;
|
|
721
|
+
|
|
722
|
+
// TypeScript enforces correct payment method names
|
|
723
|
+
paymentKit.submit({ paymentMethod: 'card' }); // ✓
|
|
724
|
+
paymentKit.submit({ paymentMethod: 'stripe' }); // ✗ Type error
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
## Troubleshooting
|
|
728
|
+
|
|
729
|
+
### Card inputs not showing
|
|
730
|
+
|
|
731
|
+
- Ensure DOM elements exist before mounting
|
|
732
|
+
- Check `baseUrl` is accessible
|
|
733
|
+
- Verify `secureToken` is valid
|
|
734
|
+
|
|
735
|
+
### PayPal popup blocked
|
|
736
|
+
|
|
737
|
+
- Instruct users to allow popups
|
|
738
|
+
- Check browser console for errors
|
|
739
|
+
- Verify `apiBaseUrl` is correct
|
|
740
|
+
|
|
741
|
+
### Google Pay not available
|
|
742
|
+
|
|
743
|
+
- Add Stripe.js script tag
|
|
744
|
+
- Test on supported devices (Android Chrome, Safari on iOS)
|
|
745
|
+
- Check `processorId` is valid
|
|
746
|
+
|
|
747
|
+
### TypeScript errors
|
|
748
|
+
|
|
749
|
+
- Ensure proper typing of PaymentKit instance
|
|
750
|
+
- Import types from correct paths
|
|
751
|
+
- Use `ReturnType<typeof PaymentKit<[...]>>` pattern
|
|
752
|
+
|
|
753
|
+
## License
|
|
754
|
+
|
|
755
|
+
MIT
|