logix-payment-shift4 1.1.2 → 1.1.4
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 +41 -0
- package/dist/index.cjs.js +40 -71
- package/dist/index.esm.js +40 -71
- package/package.json +30 -10
- package/.babelrc +0 -3
- package/rollup.config.js +0 -29
- package/src/PaymentForm.jsx +0 -217
- package/src/index.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 💳 PaymentForm (Shift4 React Payment Component)
|
|
2
|
+
|
|
3
|
+
PaymentForm is a **React component** built to accept **secure card payments** using **Shift4**.
|
|
4
|
+
It is **SPA-friendly** and handles payment results via **callback functions** instead of forced redirects.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## ✨ Features
|
|
9
|
+
|
|
10
|
+
- 🔐 Secure card tokenization (Shift4)
|
|
11
|
+
- 🛡️ 3D Secure support
|
|
12
|
+
- ⚡ Callback-based success & error handling
|
|
13
|
+
- 🎨 Fully customizable UI
|
|
14
|
+
- 📦 Library-ready component
|
|
15
|
+
- 🚀 Works with React Router / Next.js
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 📦 Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm i logix-payment-shift4
|
|
23
|
+
|
|
24
|
+
import PaymentForm from "logix-payment-shift4";
|
|
25
|
+
|
|
26
|
+
<PaymentForm
|
|
27
|
+
amount={1000}
|
|
28
|
+
currency="USD"
|
|
29
|
+
color="#0d6efd"
|
|
30
|
+
baseUrl="https://api.example.com/payment/"
|
|
31
|
+
userId="user-123"
|
|
32
|
+
description="Premium subscription"
|
|
33
|
+
|
|
34
|
+
successPage={(message) => {
|
|
35
|
+
console.log("Payment successful:", message);
|
|
36
|
+
}}
|
|
37
|
+
|
|
38
|
+
errorPage={(error) => {
|
|
39
|
+
console.error("Payment failed:", error);
|
|
40
|
+
}}
|
|
41
|
+
/>
|
package/dist/index.cjs.js
CHANGED
|
@@ -199,27 +199,17 @@ function PaymentForm(_ref) {
|
|
|
199
199
|
errorPage = _ref.errorPage,
|
|
200
200
|
description = _ref.description;
|
|
201
201
|
var formRef = React.useRef();
|
|
202
|
-
var initializedRef = React.useRef(false);
|
|
202
|
+
var initializedRef = React.useRef(false);
|
|
203
203
|
var shift4Ref = React.useRef(null);
|
|
204
204
|
var componentsRef = React.useRef(null);
|
|
205
|
-
var _useState = React.useState(
|
|
205
|
+
var _useState = React.useState(false),
|
|
206
206
|
_useState2 = _slicedToArray(_useState, 2),
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
var _useState3 = React.useState(
|
|
207
|
+
isSubmitting = _useState2[0],
|
|
208
|
+
setIsSubmitting = _useState2[1];
|
|
209
|
+
var _useState3 = React.useState(false),
|
|
210
210
|
_useState4 = _slicedToArray(_useState3, 2),
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
var _useState5 = React.useState(false),
|
|
214
|
-
_useState6 = _slicedToArray(_useState5, 2),
|
|
215
|
-
isSubmitting = _useState6[0],
|
|
216
|
-
setIsSubmitting = _useState6[1];
|
|
217
|
-
var _useState7 = React.useState(false),
|
|
218
|
-
_useState8 = _slicedToArray(_useState7, 2),
|
|
219
|
-
isReady = _useState8[0],
|
|
220
|
-
setIsReady = _useState8[1];
|
|
221
|
-
console.log(error);
|
|
222
|
-
console.log(success);
|
|
211
|
+
isReady = _useState4[0],
|
|
212
|
+
setIsReady = _useState4[1];
|
|
223
213
|
React.useEffect(function () {
|
|
224
214
|
if (initializedRef.current) return;
|
|
225
215
|
initializedRef.current = true;
|
|
@@ -234,31 +224,18 @@ function PaymentForm(_ref) {
|
|
|
234
224
|
return fetch(baseUrl + userId);
|
|
235
225
|
case 1:
|
|
236
226
|
response = _context.v;
|
|
237
|
-
if (response.ok)
|
|
238
|
-
|
|
239
|
-
break;
|
|
240
|
-
}
|
|
241
|
-
throw new Error("Failed to fetch public key");
|
|
242
|
-
case 2:
|
|
243
|
-
_context.n = 3;
|
|
227
|
+
if (!response.ok) errorPage("Failed to fetch public key");
|
|
228
|
+
_context.n = 2;
|
|
244
229
|
return response.json();
|
|
245
|
-
case
|
|
230
|
+
case 2:
|
|
246
231
|
_yield$response$json = _context.v;
|
|
247
232
|
publicKeys = _yield$response$json.publicKeys;
|
|
248
|
-
if (publicKeys)
|
|
249
|
-
_context.n = 4;
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
throw new Error("Public key is empty");
|
|
253
|
-
case 4:
|
|
254
|
-
// 🔹 2. Shift4 script-i yükləyirik
|
|
233
|
+
if (!publicKeys) errorPage("Public key is empty");
|
|
255
234
|
script = document.createElement("script");
|
|
256
235
|
script.src = "https://js.dev.shift4.com/shift4.js";
|
|
257
236
|
script.async = true;
|
|
258
237
|
script.onload = function () {
|
|
259
238
|
if (!window.Shift4) return;
|
|
260
|
-
|
|
261
|
-
// 🔹 3. Dinamik key ilə init
|
|
262
239
|
shift4Ref.current = window.Shift4(publicKeys);
|
|
263
240
|
componentsRef.current = shift4Ref.current.createComponentGroup().automount("#payment-form");
|
|
264
241
|
setIsReady(true);
|
|
@@ -267,17 +244,17 @@ function PaymentForm(_ref) {
|
|
|
267
244
|
setError("Payment provider script failed to load.");
|
|
268
245
|
};
|
|
269
246
|
document.body.appendChild(script);
|
|
270
|
-
_context.n =
|
|
247
|
+
_context.n = 4;
|
|
271
248
|
break;
|
|
272
|
-
case
|
|
273
|
-
_context.p =
|
|
249
|
+
case 3:
|
|
250
|
+
_context.p = 3;
|
|
274
251
|
_t = _context.v;
|
|
275
252
|
console.error(_t);
|
|
276
253
|
setError("Payment initialization failed. Please try again.");
|
|
277
|
-
case
|
|
254
|
+
case 4:
|
|
278
255
|
return _context.a(2);
|
|
279
256
|
}
|
|
280
|
-
}, _callee, null, [[0,
|
|
257
|
+
}, _callee, null, [[0, 3]]);
|
|
281
258
|
}));
|
|
282
259
|
return function initPayment() {
|
|
283
260
|
return _ref2.apply(this, arguments);
|
|
@@ -308,41 +285,33 @@ function PaymentForm(_ref) {
|
|
|
308
285
|
_context2.n = 3;
|
|
309
286
|
break;
|
|
310
287
|
}
|
|
311
|
-
|
|
288
|
+
errorPage("Payment form is not ready yet. Please try again.");
|
|
312
289
|
return _context2.a(2);
|
|
313
290
|
case 3:
|
|
314
|
-
setError("");
|
|
315
|
-
setSuccess("");
|
|
316
291
|
setIsSubmitting(true);
|
|
317
292
|
_context2.p = 4;
|
|
318
293
|
_context2.n = 5;
|
|
319
294
|
return shift4Ref.current.createToken(componentsRef.current);
|
|
320
295
|
case 5:
|
|
321
296
|
token = _context2.v;
|
|
322
|
-
if (token !== null && token !== void 0 && token.id) {
|
|
323
|
-
|
|
324
|
-
break;
|
|
297
|
+
if (!(token !== null && token !== void 0 && token.id)) {
|
|
298
|
+
errorPage("Card tokenization failed. Please check your details and try again.");
|
|
325
299
|
}
|
|
326
|
-
throw new Error("Card tokenization failed. Please check your details and try again.");
|
|
327
|
-
case 6:
|
|
328
300
|
request = {
|
|
329
301
|
amount: amount,
|
|
330
302
|
currency: currency,
|
|
331
303
|
card: token.id,
|
|
332
304
|
description: description
|
|
333
305
|
};
|
|
334
|
-
_context2.n =
|
|
306
|
+
_context2.n = 6;
|
|
335
307
|
return shift4Ref.current.verifyThreeDSecure(request);
|
|
336
|
-
case
|
|
308
|
+
case 6:
|
|
337
309
|
threeDSecureToken = _context2.v;
|
|
338
|
-
if (threeDSecureToken !== null && threeDSecureToken !== void 0 && threeDSecureToken.id) {
|
|
339
|
-
|
|
340
|
-
break;
|
|
310
|
+
if (!(threeDSecureToken !== null && threeDSecureToken !== void 0 && threeDSecureToken.id)) {
|
|
311
|
+
errorPage("3D Secure verification failed. Please try again.");
|
|
341
312
|
}
|
|
342
|
-
throw new Error("3D Secure verification failed. Please try again.");
|
|
343
|
-
case 8:
|
|
344
313
|
apiBase = baseUrl + "charge/" + userId;
|
|
345
|
-
_context2.n =
|
|
314
|
+
_context2.n = 7;
|
|
346
315
|
return fetch("".concat(apiBase), {
|
|
347
316
|
method: "POST",
|
|
348
317
|
headers: {
|
|
@@ -355,34 +324,34 @@ function PaymentForm(_ref) {
|
|
|
355
324
|
description: description
|
|
356
325
|
})
|
|
357
326
|
});
|
|
358
|
-
case
|
|
327
|
+
case 7:
|
|
359
328
|
response = _context2.v;
|
|
360
|
-
_context2.n =
|
|
329
|
+
_context2.n = 8;
|
|
361
330
|
return response.json();
|
|
362
|
-
case
|
|
331
|
+
case 8:
|
|
363
332
|
result = _context2.v;
|
|
364
333
|
if (response.ok) {
|
|
365
|
-
_context2.n =
|
|
334
|
+
_context2.n = 9;
|
|
366
335
|
break;
|
|
367
336
|
}
|
|
368
|
-
|
|
337
|
+
if (typeof errorPage === "function") errorPage(result);
|
|
369
338
|
return _context2.a(2);
|
|
370
|
-
case
|
|
371
|
-
|
|
372
|
-
_context2.n =
|
|
339
|
+
case 9:
|
|
340
|
+
if (typeof successPage === "function") successPage(result.message);
|
|
341
|
+
_context2.n = 11;
|
|
373
342
|
break;
|
|
374
|
-
case
|
|
375
|
-
_context2.p =
|
|
343
|
+
case 10:
|
|
344
|
+
_context2.p = 10;
|
|
376
345
|
_t2 = _context2.v;
|
|
377
|
-
|
|
378
|
-
case
|
|
379
|
-
_context2.p =
|
|
346
|
+
if (typeof errorPage === "function") errorPage(_t2.message);
|
|
347
|
+
case 11:
|
|
348
|
+
_context2.p = 11;
|
|
380
349
|
setIsSubmitting(false);
|
|
381
|
-
return _context2.f(
|
|
382
|
-
case
|
|
350
|
+
return _context2.f(11);
|
|
351
|
+
case 12:
|
|
383
352
|
return _context2.a(2);
|
|
384
353
|
}
|
|
385
|
-
}, _callee2, null, [[4,
|
|
354
|
+
}, _callee2, null, [[4, 10, 11, 12]]);
|
|
386
355
|
}));
|
|
387
356
|
return function handleSubmit(_x) {
|
|
388
357
|
return _ref3.apply(this, arguments);
|
package/dist/index.esm.js
CHANGED
|
@@ -197,27 +197,17 @@ function PaymentForm(_ref) {
|
|
|
197
197
|
errorPage = _ref.errorPage,
|
|
198
198
|
description = _ref.description;
|
|
199
199
|
var formRef = useRef();
|
|
200
|
-
var initializedRef = useRef(false);
|
|
200
|
+
var initializedRef = useRef(false);
|
|
201
201
|
var shift4Ref = useRef(null);
|
|
202
202
|
var componentsRef = useRef(null);
|
|
203
|
-
var _useState = useState(
|
|
203
|
+
var _useState = useState(false),
|
|
204
204
|
_useState2 = _slicedToArray(_useState, 2),
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
var _useState3 = useState(
|
|
205
|
+
isSubmitting = _useState2[0],
|
|
206
|
+
setIsSubmitting = _useState2[1];
|
|
207
|
+
var _useState3 = useState(false),
|
|
208
208
|
_useState4 = _slicedToArray(_useState3, 2),
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
var _useState5 = useState(false),
|
|
212
|
-
_useState6 = _slicedToArray(_useState5, 2),
|
|
213
|
-
isSubmitting = _useState6[0],
|
|
214
|
-
setIsSubmitting = _useState6[1];
|
|
215
|
-
var _useState7 = useState(false),
|
|
216
|
-
_useState8 = _slicedToArray(_useState7, 2),
|
|
217
|
-
isReady = _useState8[0],
|
|
218
|
-
setIsReady = _useState8[1];
|
|
219
|
-
console.log(error);
|
|
220
|
-
console.log(success);
|
|
209
|
+
isReady = _useState4[0],
|
|
210
|
+
setIsReady = _useState4[1];
|
|
221
211
|
useEffect(function () {
|
|
222
212
|
if (initializedRef.current) return;
|
|
223
213
|
initializedRef.current = true;
|
|
@@ -232,31 +222,18 @@ function PaymentForm(_ref) {
|
|
|
232
222
|
return fetch(baseUrl + userId);
|
|
233
223
|
case 1:
|
|
234
224
|
response = _context.v;
|
|
235
|
-
if (response.ok)
|
|
236
|
-
|
|
237
|
-
break;
|
|
238
|
-
}
|
|
239
|
-
throw new Error("Failed to fetch public key");
|
|
240
|
-
case 2:
|
|
241
|
-
_context.n = 3;
|
|
225
|
+
if (!response.ok) errorPage("Failed to fetch public key");
|
|
226
|
+
_context.n = 2;
|
|
242
227
|
return response.json();
|
|
243
|
-
case
|
|
228
|
+
case 2:
|
|
244
229
|
_yield$response$json = _context.v;
|
|
245
230
|
publicKeys = _yield$response$json.publicKeys;
|
|
246
|
-
if (publicKeys)
|
|
247
|
-
_context.n = 4;
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
throw new Error("Public key is empty");
|
|
251
|
-
case 4:
|
|
252
|
-
// 🔹 2. Shift4 script-i yükləyirik
|
|
231
|
+
if (!publicKeys) errorPage("Public key is empty");
|
|
253
232
|
script = document.createElement("script");
|
|
254
233
|
script.src = "https://js.dev.shift4.com/shift4.js";
|
|
255
234
|
script.async = true;
|
|
256
235
|
script.onload = function () {
|
|
257
236
|
if (!window.Shift4) return;
|
|
258
|
-
|
|
259
|
-
// 🔹 3. Dinamik key ilə init
|
|
260
237
|
shift4Ref.current = window.Shift4(publicKeys);
|
|
261
238
|
componentsRef.current = shift4Ref.current.createComponentGroup().automount("#payment-form");
|
|
262
239
|
setIsReady(true);
|
|
@@ -265,17 +242,17 @@ function PaymentForm(_ref) {
|
|
|
265
242
|
setError("Payment provider script failed to load.");
|
|
266
243
|
};
|
|
267
244
|
document.body.appendChild(script);
|
|
268
|
-
_context.n =
|
|
245
|
+
_context.n = 4;
|
|
269
246
|
break;
|
|
270
|
-
case
|
|
271
|
-
_context.p =
|
|
247
|
+
case 3:
|
|
248
|
+
_context.p = 3;
|
|
272
249
|
_t = _context.v;
|
|
273
250
|
console.error(_t);
|
|
274
251
|
setError("Payment initialization failed. Please try again.");
|
|
275
|
-
case
|
|
252
|
+
case 4:
|
|
276
253
|
return _context.a(2);
|
|
277
254
|
}
|
|
278
|
-
}, _callee, null, [[0,
|
|
255
|
+
}, _callee, null, [[0, 3]]);
|
|
279
256
|
}));
|
|
280
257
|
return function initPayment() {
|
|
281
258
|
return _ref2.apply(this, arguments);
|
|
@@ -306,41 +283,33 @@ function PaymentForm(_ref) {
|
|
|
306
283
|
_context2.n = 3;
|
|
307
284
|
break;
|
|
308
285
|
}
|
|
309
|
-
|
|
286
|
+
errorPage("Payment form is not ready yet. Please try again.");
|
|
310
287
|
return _context2.a(2);
|
|
311
288
|
case 3:
|
|
312
|
-
setError("");
|
|
313
|
-
setSuccess("");
|
|
314
289
|
setIsSubmitting(true);
|
|
315
290
|
_context2.p = 4;
|
|
316
291
|
_context2.n = 5;
|
|
317
292
|
return shift4Ref.current.createToken(componentsRef.current);
|
|
318
293
|
case 5:
|
|
319
294
|
token = _context2.v;
|
|
320
|
-
if (token !== null && token !== void 0 && token.id) {
|
|
321
|
-
|
|
322
|
-
break;
|
|
295
|
+
if (!(token !== null && token !== void 0 && token.id)) {
|
|
296
|
+
errorPage("Card tokenization failed. Please check your details and try again.");
|
|
323
297
|
}
|
|
324
|
-
throw new Error("Card tokenization failed. Please check your details and try again.");
|
|
325
|
-
case 6:
|
|
326
298
|
request = {
|
|
327
299
|
amount: amount,
|
|
328
300
|
currency: currency,
|
|
329
301
|
card: token.id,
|
|
330
302
|
description: description
|
|
331
303
|
};
|
|
332
|
-
_context2.n =
|
|
304
|
+
_context2.n = 6;
|
|
333
305
|
return shift4Ref.current.verifyThreeDSecure(request);
|
|
334
|
-
case
|
|
306
|
+
case 6:
|
|
335
307
|
threeDSecureToken = _context2.v;
|
|
336
|
-
if (threeDSecureToken !== null && threeDSecureToken !== void 0 && threeDSecureToken.id) {
|
|
337
|
-
|
|
338
|
-
break;
|
|
308
|
+
if (!(threeDSecureToken !== null && threeDSecureToken !== void 0 && threeDSecureToken.id)) {
|
|
309
|
+
errorPage("3D Secure verification failed. Please try again.");
|
|
339
310
|
}
|
|
340
|
-
throw new Error("3D Secure verification failed. Please try again.");
|
|
341
|
-
case 8:
|
|
342
311
|
apiBase = baseUrl + "charge/" + userId;
|
|
343
|
-
_context2.n =
|
|
312
|
+
_context2.n = 7;
|
|
344
313
|
return fetch("".concat(apiBase), {
|
|
345
314
|
method: "POST",
|
|
346
315
|
headers: {
|
|
@@ -353,34 +322,34 @@ function PaymentForm(_ref) {
|
|
|
353
322
|
description: description
|
|
354
323
|
})
|
|
355
324
|
});
|
|
356
|
-
case
|
|
325
|
+
case 7:
|
|
357
326
|
response = _context2.v;
|
|
358
|
-
_context2.n =
|
|
327
|
+
_context2.n = 8;
|
|
359
328
|
return response.json();
|
|
360
|
-
case
|
|
329
|
+
case 8:
|
|
361
330
|
result = _context2.v;
|
|
362
331
|
if (response.ok) {
|
|
363
|
-
_context2.n =
|
|
332
|
+
_context2.n = 9;
|
|
364
333
|
break;
|
|
365
334
|
}
|
|
366
|
-
|
|
335
|
+
if (typeof errorPage === "function") errorPage(result);
|
|
367
336
|
return _context2.a(2);
|
|
368
|
-
case
|
|
369
|
-
|
|
370
|
-
_context2.n =
|
|
337
|
+
case 9:
|
|
338
|
+
if (typeof successPage === "function") successPage(result.message);
|
|
339
|
+
_context2.n = 11;
|
|
371
340
|
break;
|
|
372
|
-
case
|
|
373
|
-
_context2.p =
|
|
341
|
+
case 10:
|
|
342
|
+
_context2.p = 10;
|
|
374
343
|
_t2 = _context2.v;
|
|
375
|
-
|
|
376
|
-
case
|
|
377
|
-
_context2.p =
|
|
344
|
+
if (typeof errorPage === "function") errorPage(_t2.message);
|
|
345
|
+
case 11:
|
|
346
|
+
_context2.p = 11;
|
|
378
347
|
setIsSubmitting(false);
|
|
379
|
-
return _context2.f(
|
|
380
|
-
case
|
|
348
|
+
return _context2.f(11);
|
|
349
|
+
case 12:
|
|
381
350
|
return _context2.a(2);
|
|
382
351
|
}
|
|
383
|
-
}, _callee2, null, [[4,
|
|
352
|
+
}, _callee2, null, [[4, 10, 11, 12]]);
|
|
384
353
|
}));
|
|
385
354
|
return function handleSubmit(_x) {
|
|
386
355
|
return _ref3.apply(this, arguments);
|
package/package.json
CHANGED
|
@@ -1,20 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "logix-payment-shift4",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"main": "dist/index.cjs.js",
|
|
5
|
-
"module": "dist/index.esm.js",
|
|
3
|
+
"version": "1.1.4",
|
|
6
4
|
"description": "A React component library for integrating Shift4 payments with Logix applications.",
|
|
5
|
+
"author": "Yusif Atababayev",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
|
|
7
8
|
"type": "module",
|
|
9
|
+
|
|
10
|
+
"main": "dist/index.cjs.js",
|
|
11
|
+
"module": "dist/index.esm.js",
|
|
12
|
+
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
|
|
8
18
|
"scripts": {
|
|
9
19
|
"build": "rollup -c"
|
|
10
20
|
},
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
"
|
|
21
|
+
|
|
22
|
+
"keywords": [
|
|
23
|
+
"react",
|
|
24
|
+
"payment",
|
|
25
|
+
"shift4",
|
|
26
|
+
"checkout",
|
|
27
|
+
"3d-secure",
|
|
28
|
+
"react-component",
|
|
29
|
+
"payment-gateway"
|
|
30
|
+
],
|
|
31
|
+
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"react": ">=18",
|
|
34
|
+
"react-dom": ">=18"
|
|
17
35
|
},
|
|
36
|
+
|
|
18
37
|
"devDependencies": {
|
|
19
38
|
"@babel/core": "^7.28.5",
|
|
20
39
|
"@babel/preset-env": "^7.28.5",
|
|
@@ -24,4 +43,5 @@
|
|
|
24
43
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
25
44
|
"rollup": "^4.55.1"
|
|
26
45
|
}
|
|
27
|
-
|
|
46
|
+
|
|
47
|
+
}
|
package/.babelrc
DELETED
package/rollup.config.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import resolve from "@rollup/plugin-node-resolve";
|
|
2
|
-
import commonjs from "@rollup/plugin-commonjs";
|
|
3
|
-
import babel from "@rollup/plugin-babel";
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
input: "src/index.js",
|
|
7
|
-
output: [
|
|
8
|
-
{
|
|
9
|
-
file: "dist/index.cjs.js",
|
|
10
|
-
format: "cjs",
|
|
11
|
-
exports: "named"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
file: "dist/index.esm.js",
|
|
15
|
-
format: "esm"
|
|
16
|
-
}
|
|
17
|
-
],
|
|
18
|
-
external: ["react", "react-dom"],
|
|
19
|
-
plugins: [
|
|
20
|
-
resolve({
|
|
21
|
-
extensions: [".js", ".jsx", ".ts", ".tsx"]
|
|
22
|
-
}),
|
|
23
|
-
commonjs(),
|
|
24
|
-
babel({
|
|
25
|
-
babelHelpers: "bundled",
|
|
26
|
-
exclude: "node_modules/**"
|
|
27
|
-
})
|
|
28
|
-
]
|
|
29
|
-
};
|
package/src/PaymentForm.jsx
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
-
|
|
3
|
-
export default function PaymentForm({ amount, currency, color, formwidth = 400, formborderRadius = 20, formbackgroundColor = "#fff", inputpadding = 12, baseUrl, userId, successPage, errorPage,description }) {
|
|
4
|
-
const formRef = useRef();
|
|
5
|
-
const initializedRef = useRef(false); // yalnız bir dəfə mount üçün
|
|
6
|
-
const shift4Ref = useRef(null);
|
|
7
|
-
const componentsRef = useRef(null);
|
|
8
|
-
const [error, setError] = useState("");
|
|
9
|
-
const [success, setSuccess] = useState("");
|
|
10
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
11
|
-
const [isReady, setIsReady] = useState(false);
|
|
12
|
-
console.log(error);
|
|
13
|
-
console.log(success);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
if (initializedRef.current) return;
|
|
18
|
-
initializedRef.current = true;
|
|
19
|
-
|
|
20
|
-
const initPayment = async () => {
|
|
21
|
-
try {
|
|
22
|
-
// 🔹 1. Public key-ni backend-dən çəkirik
|
|
23
|
-
const response = await fetch(baseUrl + userId);
|
|
24
|
-
if (!response.ok) throw new Error("Failed to fetch public key");
|
|
25
|
-
|
|
26
|
-
const { publicKeys } = await response.json();
|
|
27
|
-
if (!publicKeys) throw new Error("Public key is empty");
|
|
28
|
-
|
|
29
|
-
// 🔹 2. Shift4 script-i yükləyirik
|
|
30
|
-
const script = document.createElement("script");
|
|
31
|
-
script.src = "https://js.dev.shift4.com/shift4.js";
|
|
32
|
-
script.async = true;
|
|
33
|
-
|
|
34
|
-
script.onload = () => {
|
|
35
|
-
if (!window.Shift4) return;
|
|
36
|
-
|
|
37
|
-
// 🔹 3. Dinamik key ilə init
|
|
38
|
-
shift4Ref.current = window.Shift4(publicKeys);
|
|
39
|
-
|
|
40
|
-
componentsRef.current = shift4Ref.current
|
|
41
|
-
.createComponentGroup()
|
|
42
|
-
.automount("#payment-form");
|
|
43
|
-
|
|
44
|
-
setIsReady(true);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
script.onerror = () => {
|
|
48
|
-
setError("Payment provider script failed to load.");
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
document.body.appendChild(script);
|
|
52
|
-
} catch (err) {
|
|
53
|
-
console.error(err);
|
|
54
|
-
setError("Payment initialization failed. Please try again.");
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
initPayment();
|
|
59
|
-
}, []);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const handleSubmit = async (e) => {
|
|
63
|
-
e.preventDefault();
|
|
64
|
-
|
|
65
|
-
if (isSubmitting) return;
|
|
66
|
-
if (!formRef.current) return;
|
|
67
|
-
|
|
68
|
-
if (!shift4Ref.current || !componentsRef.current) {
|
|
69
|
-
setError("Payment form is not ready yet. Please try again.");
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
setError("");
|
|
74
|
-
setSuccess("");
|
|
75
|
-
setIsSubmitting(true);
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
const token = await shift4Ref.current.createToken(componentsRef.current);
|
|
79
|
-
if (!token?.id) {
|
|
80
|
-
throw new Error("Card tokenization failed. Please check your details and try again.");
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const request = {
|
|
84
|
-
amount: amount,
|
|
85
|
-
currency: currency,
|
|
86
|
-
card: token.id,
|
|
87
|
-
description
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const threeDSecureToken = await shift4Ref.current.verifyThreeDSecure(request);
|
|
91
|
-
if (!threeDSecureToken?.id) {
|
|
92
|
-
throw new Error("3D Secure verification failed. Please try again.");
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const apiBase = baseUrl + "charge/" + userId;
|
|
96
|
-
const response = await fetch(`${apiBase}`, {
|
|
97
|
-
method: "POST",
|
|
98
|
-
headers: {
|
|
99
|
-
"Content-Type": "application/json",
|
|
100
|
-
},
|
|
101
|
-
body: JSON.stringify({
|
|
102
|
-
tokenId: threeDSecureToken.id,
|
|
103
|
-
amount: request.amount,
|
|
104
|
-
currency: request.currency,
|
|
105
|
-
description
|
|
106
|
-
}),
|
|
107
|
-
});
|
|
108
|
-
const result = await response.json();
|
|
109
|
-
if (!response.ok) {
|
|
110
|
-
window.location.href = `${errorPage}?message=${encodeURIComponent(result.message)}`;
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
window.location.href = `${successPage}?message=${encodeURIComponent(result.message)}`;
|
|
115
|
-
|
|
116
|
-
} catch (err) {
|
|
117
|
-
window.location.href = `${errorPage}?message=${encodeURIComponent(err.message)}`;
|
|
118
|
-
} finally {
|
|
119
|
-
setIsSubmitting(false);
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
return (
|
|
124
|
-
<div
|
|
125
|
-
style={{
|
|
126
|
-
display: "flex",
|
|
127
|
-
justifyContent: "center",
|
|
128
|
-
width: "100%",
|
|
129
|
-
boxSizing: "border-box"
|
|
130
|
-
}}
|
|
131
|
-
>
|
|
132
|
-
<form
|
|
133
|
-
ref={formRef}
|
|
134
|
-
id="payment-form"
|
|
135
|
-
onSubmit={handleSubmit}
|
|
136
|
-
method="post"
|
|
137
|
-
style={{
|
|
138
|
-
display: "grid",
|
|
139
|
-
gap: "12px",
|
|
140
|
-
padding: "20px",
|
|
141
|
-
backgroundColor: formbackgroundColor,
|
|
142
|
-
borderRadius: formborderRadius,
|
|
143
|
-
width: formwidth,
|
|
144
|
-
boxSizing: "border-box"
|
|
145
|
-
}}
|
|
146
|
-
>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
{/* Card Number */}
|
|
150
|
-
<div style={{ display: "grid", gap: "8px" }}>
|
|
151
|
-
<label style={{ fontWeight: "500", color: "#555" }}>Card number</label>
|
|
152
|
-
<div
|
|
153
|
-
data-shift4="number"
|
|
154
|
-
className="form-control"
|
|
155
|
-
style={{
|
|
156
|
-
padding: inputpadding,
|
|
157
|
-
borderRadius: formborderRadius,
|
|
158
|
-
border: "1px solid #ccc",
|
|
159
|
-
boxShadow: "inset 0 2px 4px rgba(0,0,0,0.05)"
|
|
160
|
-
}}
|
|
161
|
-
/>
|
|
162
|
-
</div>
|
|
163
|
-
|
|
164
|
-
{/* Expiration + CVC */}
|
|
165
|
-
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "10px", marginTop: "5px" }}>
|
|
166
|
-
<div>
|
|
167
|
-
<label style={{ fontWeight: "500", color: "#555", marginBottom: 2 }}>Expiration</label>
|
|
168
|
-
<div
|
|
169
|
-
data-shift4="expiry"
|
|
170
|
-
className="form-control"
|
|
171
|
-
style={{
|
|
172
|
-
padding: inputpadding,
|
|
173
|
-
borderRadius: formborderRadius,
|
|
174
|
-
border: "1px solid #ccc",
|
|
175
|
-
boxShadow: "inset 0 2px 4px rgba(0,0,0,0.05)"
|
|
176
|
-
}}
|
|
177
|
-
/>
|
|
178
|
-
</div>
|
|
179
|
-
<div>
|
|
180
|
-
<label style={{ fontWeight: "500", color: "#555", marginBottom: 2 }}>CVC</label>
|
|
181
|
-
<div
|
|
182
|
-
data-shift4="cvc"
|
|
183
|
-
className="form-control"
|
|
184
|
-
style={{
|
|
185
|
-
padding: inputpadding,
|
|
186
|
-
borderRadius: formborderRadius,
|
|
187
|
-
border: "1px solid #ccc",
|
|
188
|
-
boxShadow: "inset 0 2px 4px rgba(0,0,0,0.05)"
|
|
189
|
-
}}
|
|
190
|
-
/>
|
|
191
|
-
</div>
|
|
192
|
-
</div>
|
|
193
|
-
|
|
194
|
-
{/* Submit Button */}
|
|
195
|
-
<button
|
|
196
|
-
type="submit"
|
|
197
|
-
disabled={!isReady || isSubmitting}
|
|
198
|
-
style={{
|
|
199
|
-
marginTop: "16px",
|
|
200
|
-
width: "100%",
|
|
201
|
-
padding: inputpadding + 2,
|
|
202
|
-
backgroundColor: color,
|
|
203
|
-
color: "white",
|
|
204
|
-
border: "none",
|
|
205
|
-
borderRadius: formborderRadius,
|
|
206
|
-
fontWeight: "600",
|
|
207
|
-
cursor: !isReady || isSubmitting ? "not-allowed" : "pointer",
|
|
208
|
-
opacity: !isReady || isSubmitting ? 0.7 : 1
|
|
209
|
-
}}
|
|
210
|
-
>
|
|
211
|
-
{isSubmitting ? "Processing..." : "Buy now"}
|
|
212
|
-
</button>
|
|
213
|
-
</form>
|
|
214
|
-
</div>
|
|
215
|
-
|
|
216
|
-
);
|
|
217
|
-
}
|
package/src/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default as PaymentForm } from "./PaymentForm";
|