tonder-web-sdk 1.4.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.
Files changed (83) hide show
  1. package/.env-example +1 -0
  2. package/.htaccess +1 -0
  3. package/README.md +204 -0
  4. package/cypress/e2e/1-getting-started/todo.cy.js +143 -0
  5. package/cypress/e2e/2-advanced-examples/actions.cy.js +299 -0
  6. package/cypress/e2e/2-advanced-examples/aliasing.cy.js +39 -0
  7. package/cypress/e2e/2-advanced-examples/assertions.cy.js +176 -0
  8. package/cypress/e2e/2-advanced-examples/connectors.cy.js +98 -0
  9. package/cypress/e2e/2-advanced-examples/cookies.cy.js +118 -0
  10. package/cypress/e2e/2-advanced-examples/cypress_api.cy.js +185 -0
  11. package/cypress/e2e/2-advanced-examples/files.cy.js +85 -0
  12. package/cypress/e2e/2-advanced-examples/location.cy.js +32 -0
  13. package/cypress/e2e/2-advanced-examples/misc.cy.js +104 -0
  14. package/cypress/e2e/2-advanced-examples/navigation.cy.js +56 -0
  15. package/cypress/e2e/2-advanced-examples/network_requests.cy.js +163 -0
  16. package/cypress/e2e/2-advanced-examples/querying.cy.js +114 -0
  17. package/cypress/e2e/2-advanced-examples/spies_stubs_clocks.cy.js +201 -0
  18. package/cypress/e2e/2-advanced-examples/storage.cy.js +110 -0
  19. package/cypress/e2e/2-advanced-examples/traversal.cy.js +121 -0
  20. package/cypress/e2e/2-advanced-examples/utilities.cy.js +108 -0
  21. package/cypress/e2e/2-advanced-examples/viewport.cy.js +58 -0
  22. package/cypress/e2e/2-advanced-examples/waiting.cy.js +30 -0
  23. package/cypress/e2e/2-advanced-examples/window.cy.js +22 -0
  24. package/cypress/fixtures/example.json +5 -0
  25. package/cypress/support/commands.js +25 -0
  26. package/cypress/support/e2e.js +20 -0
  27. package/cypress.config.js +9 -0
  28. package/index.html +178 -0
  29. package/index.js.example +50 -0
  30. package/package.json +29 -0
  31. package/samples/react/README.md +70 -0
  32. package/samples/react/build/asset-manifest.json +16 -0
  33. package/samples/react/build/favicon.ico +0 -0
  34. package/samples/react/build/index.html +1 -0
  35. package/samples/react/build/logo192.png +0 -0
  36. package/samples/react/build/logo512.png +0 -0
  37. package/samples/react/build/manifest.json +25 -0
  38. package/samples/react/build/robots.txt +3 -0
  39. package/samples/react/build/static/css/main.073c9b0a.css +2 -0
  40. package/samples/react/build/static/css/main.073c9b0a.css.map +1 -0
  41. package/samples/react/build/static/js/787.b83ed06f.chunk.js +2 -0
  42. package/samples/react/build/static/js/787.b83ed06f.chunk.js.map +1 -0
  43. package/samples/react/build/static/js/main.0a848807.js +3 -0
  44. package/samples/react/build/static/js/main.0a848807.js.LICENSE.txt +39 -0
  45. package/samples/react/build/static/js/main.0a848807.js.map +1 -0
  46. package/samples/react/build/static/media/sdk-icons.b491623214b2af4cccdb.png +0 -0
  47. package/samples/react/package-lock.json +28973 -0
  48. package/samples/react/package.json +44 -0
  49. package/samples/react/public/favicon.ico +0 -0
  50. package/samples/react/public/index.html +43 -0
  51. package/samples/react/public/logo192.png +0 -0
  52. package/samples/react/public/logo512.png +0 -0
  53. package/samples/react/public/manifest.json +25 -0
  54. package/samples/react/public/robots.txt +3 -0
  55. package/samples/react/src/App.css +38 -0
  56. package/samples/react/src/App.js +22 -0
  57. package/samples/react/src/App.test.js +8 -0
  58. package/samples/react/src/assets/img/sdk-icons.png +0 -0
  59. package/samples/react/src/components/Cart.js +29 -0
  60. package/samples/react/src/components/ProductCard.js +27 -0
  61. package/samples/react/src/context/CartContext.js +116 -0
  62. package/samples/react/src/index.css +13 -0
  63. package/samples/react/src/index.js +17 -0
  64. package/samples/react/src/logo.svg +1 -0
  65. package/samples/react/src/reportWebVitals.js +13 -0
  66. package/samples/react/src/screens/Checkout.js +82 -0
  67. package/samples/react/src/screens/Store.js +21 -0
  68. package/samples/react/src/setupTests.js +5 -0
  69. package/samples/react/src/storeProducts.js +30 -0
  70. package/src/classes/3dsHandler.js +203 -0
  71. package/src/classes/checkout.js +125 -0
  72. package/src/classes/inlineCheckout.js +349 -0
  73. package/src/data/api.js +109 -0
  74. package/src/helpers/skyflow.js +139 -0
  75. package/src/helpers/styles.js +61 -0
  76. package/src/helpers/template.js +112 -0
  77. package/src/helpers/utils.js +68 -0
  78. package/src/index-dev.js +129 -0
  79. package/src/index.html +58 -0
  80. package/src/index.js +7 -0
  81. package/success.html +22 -0
  82. package/v1/bundle.min.js +18 -0
  83. package/webpack.config.js +66 -0
@@ -0,0 +1,109 @@
1
+ export async function getOpenpayDeviceSessionID(merchant_id, public_key, signal) {
2
+ let openpay = await window.OpenPay;
3
+ openpay.setId(merchant_id);
4
+ openpay.setApiKey(public_key);
5
+ openpay.setSandboxMode(true);
6
+ var response = await openpay.deviceData.setup({signal});
7
+ return response;
8
+ }
9
+
10
+ export async function getBusiness(baseUrlTonder, apiKeyTonder, signal) {
11
+ const getBusiness = await fetch(
12
+ `${baseUrlTonder}/api/v1/payments/business/${apiKeyTonder}`,
13
+ {
14
+ headers: {
15
+ Authorization: `Token ${apiKeyTonder}`,
16
+ },
17
+ signal: signal,
18
+ }
19
+ );
20
+ const response = await getBusiness.json();
21
+ return response
22
+ }
23
+
24
+ export async function customerRegister(baseUrlTonder, apiKeyTonder, customer, signal) {
25
+ const url = `${baseUrlTonder}/api/v1/customer/`;
26
+ const data = {
27
+ email: customer.email,
28
+ first_name: customer?.firstName,
29
+ last_name: customer?.lastName,
30
+ phone: customer?.phone,
31
+ }
32
+ const response = await fetch(url, {
33
+ method: "POST",
34
+ headers: {
35
+ "Content-Type": "application/json",
36
+ Authorization: `Token ${apiKeyTonder}`,
37
+ },
38
+ signal: signal,
39
+ body: JSON.stringify(data),
40
+ });
41
+
42
+ if (response.status === 201) {
43
+ const jsonResponse = await response.json();
44
+ return jsonResponse;
45
+ } else {
46
+ throw new Error(`Error: ${response.statusText}`);
47
+ }
48
+ }
49
+
50
+ export async function createOrder(baseUrlTonder, apiKeyTonder, orderItems) {
51
+ const url = `${baseUrlTonder}/api/v1/orders/`;
52
+ const data = orderItems;
53
+ const response = await fetch(url, {
54
+ method: "POST",
55
+ headers: {
56
+ "Content-Type": "application/json",
57
+ Authorization: `Token ${apiKeyTonder}`,
58
+ },
59
+ body: JSON.stringify(data),
60
+ });
61
+ if (response.status === 201) {
62
+ const jsonResponse = await response.json();
63
+ return jsonResponse;
64
+ } else {
65
+ throw new Error(`Error: ${response.statusText}`);
66
+ }
67
+ }
68
+
69
+ export async function createPayment(baseUrlTonder, apiKeyTonder, paymentItems) {
70
+ const url = `${baseUrlTonder}/api/v1/business/${paymentItems.business_pk}/payments/`;
71
+ const data = paymentItems;
72
+ const response = await fetch(url, {
73
+ method: "POST",
74
+ headers: {
75
+ "Content-Type": "application/json",
76
+ Authorization: `Token ${apiKeyTonder}`,
77
+ },
78
+ body: JSON.stringify(data),
79
+ });
80
+ if (response.status >= 200 && response.status <=299) {
81
+ const jsonResponse = await response.json();
82
+ return jsonResponse;
83
+ } else {
84
+ throw new Error(`Error: ${response.statusText}`);
85
+ }
86
+ }
87
+
88
+ export async function startCheckoutRouter(baseUrlTonder, apiKeyTonder, routerItems) {
89
+ try {
90
+ const url = `${baseUrlTonder}/api/v1/checkout-router/`;
91
+ const data = routerItems;
92
+ const response = await fetch(url, {
93
+ method: "POST",
94
+ headers: {
95
+ "Content-Type": "application/json",
96
+ Authorization: `Token ${apiKeyTonder}`,
97
+ },
98
+ body: JSON.stringify(data),
99
+ });
100
+ if (response.status >= 200 && response.status <= 299) {
101
+ const jsonResponse = await response.json();
102
+ return jsonResponse;
103
+ } else {
104
+ throw new Error("Failed to start checkout router")
105
+ }
106
+ } catch (error) {
107
+ throw error
108
+ }
109
+ }
@@ -0,0 +1,139 @@
1
+ import { defaultStyles } from "./styles";
2
+
3
+ export async function initSkyflow(
4
+ vaultId,
5
+ vaultUrl,
6
+ baseUrl,
7
+ apiKey,
8
+ signal,
9
+ customStyles = {}
10
+ ) {
11
+ const skyflow = await Skyflow.init({
12
+ vaultID: vaultId,
13
+ vaultURL: vaultUrl,
14
+ getBearerToken: async () => {
15
+ // Pass the signal to the fetch call
16
+ const response = await fetch(`${baseUrl}/api/v1/vault-token/`, {
17
+ method: 'GET',
18
+ headers: {
19
+ 'Authorization': `Token ${apiKey}`,
20
+ },
21
+ signal: signal,
22
+ });
23
+
24
+ if (response.ok) {
25
+ const responseBody = await response.json();
26
+ return responseBody.token;
27
+ } else {
28
+ throw new Error('Failed to retrieve bearer token');
29
+ }
30
+ },
31
+ options: {
32
+ logLevel: Skyflow.LogLevel.ERROR,
33
+ env: Skyflow.Env.DEV,
34
+ },
35
+ });
36
+
37
+ // Create collect Container.
38
+ const collectContainer = await skyflow.container(
39
+ Skyflow.ContainerType.COLLECT
40
+ );
41
+
42
+ // Custom styles for collect elements.
43
+ var collectStylesOptions = Object.keys(customStyles).length === 0 ? defaultStyles : customStyles
44
+
45
+ const stylesForCardNumber = { ...collectStylesOptions.inputStyles.base };
46
+ stylesForCardNumber.textIndent = '44px';
47
+
48
+ const lengthMatchRule = {
49
+ type: Skyflow.ValidationRuleType.LENGTH_MATCH_RULE,
50
+ params: {
51
+ max: 70,
52
+ },
53
+ };
54
+
55
+ const cardHolderNameElement = await collectContainer.create({
56
+ table: "cards",
57
+ column: "cardholder_name",
58
+ ...collectStylesOptions,
59
+ label: collectStylesOptions.labels?.nameLabel,
60
+ placeholder: collectStylesOptions.placeholders?.namePlaceholder,
61
+ type: Skyflow.ElementType.CARDHOLDER_NAME,
62
+ validations: [lengthMatchRule],
63
+ });
64
+
65
+ cardHolderNameElement.setError('Inválido')
66
+
67
+ // Create collect elements.
68
+ const cardNumberElement = await collectContainer.create({
69
+ table: "cards",
70
+ column: "card_number",
71
+ ...collectStylesOptions,
72
+ inputStyles: {
73
+ ...collectStylesOptions.inputStyles,
74
+ base: stylesForCardNumber
75
+ },
76
+ label: collectStylesOptions.labels?.cardLabel,
77
+ placeholder: collectStylesOptions.placeholders?.cardPlaceholder,
78
+ type: Skyflow.ElementType.CARD_NUMBER,
79
+ });
80
+
81
+ cardNumberElement.setError('Inválido')
82
+
83
+ const cvvElement = await collectContainer.create({
84
+ table: "cards",
85
+ column: "cvv",
86
+ ...collectStylesOptions,
87
+ label: collectStylesOptions.labels?.cvvLabel,
88
+ placeholder: collectStylesOptions.placeholders?.cvvPlaceholder,
89
+ type: Skyflow.ElementType.CVV,
90
+ });
91
+
92
+ cvvElement.setError('Inválido')
93
+
94
+ const expiryMonthElement = await collectContainer.create({
95
+ table: "cards",
96
+ column: "expiration_month",
97
+ ...collectStylesOptions,
98
+ label: collectStylesOptions.labels?.expiryDateLabel,
99
+ placeholder: collectStylesOptions.placeholders?.expiryMonthPlaceholder,
100
+ type: Skyflow.ElementType.EXPIRATION_MONTH,
101
+ });
102
+
103
+ expiryMonthElement.setError('Inválido')
104
+
105
+ const expiryYearElement = await collectContainer.create({
106
+ table: "cards",
107
+ column: "expiration_year",
108
+ ...collectStylesOptions,
109
+ label: "",
110
+ placeholder: collectStylesOptions.placeholders?.expiryYearPlaceholder,
111
+ type: Skyflow.ElementType.EXPIRATION_YEAR,
112
+ });
113
+
114
+ expiryYearElement.setError('Inválido')
115
+
116
+ await mountElements(
117
+ cardNumberElement,
118
+ cvvElement,
119
+ expiryMonthElement,
120
+ expiryYearElement,
121
+ cardHolderNameElement,
122
+ )
123
+
124
+ return collectContainer
125
+ }
126
+
127
+ async function mountElements(
128
+ cardNumberElement,
129
+ cvvElement,
130
+ expiryMonthElement,
131
+ expiryYearElement,
132
+ cardHolderNameElement,
133
+ ) {
134
+ cardNumberElement.mount("#collectCardNumber");
135
+ cvvElement.mount("#collectCvv");
136
+ expiryMonthElement.mount("#collectExpirationMonth");
137
+ expiryYearElement.mount("#collectExpirationYear");
138
+ cardHolderNameElement.mount("#collectCardholderName");
139
+ }
@@ -0,0 +1,61 @@
1
+ export const defaultStyles = {
2
+ inputStyles: {
3
+ base: {
4
+ border: "1px solid #e0e0e0",
5
+ padding: "10px 7px",
6
+ borderRadius: "5px",
7
+ color: "#1d1d1d",
8
+ marginTop: "2px",
9
+ backgroundColor: "white",
10
+ fontFamily: '"Inter", sans-serif',
11
+ fontSize: '16px',
12
+ '&::placeholder': {
13
+ color: "#ccc",
14
+ },
15
+ },
16
+ cardIcon: {
17
+ position: 'absolute',
18
+ left: '6px',
19
+ bottom: 'calc(50% - 12px)',
20
+ },
21
+ complete: {
22
+ color: "#4caf50",
23
+ },
24
+ empty: {},
25
+ focus: {},
26
+ invalid: {
27
+ border: "1px solid #f44336",
28
+ },
29
+ global: {
30
+ '@import': 'url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;700&display=swap")',
31
+ }
32
+ },
33
+ labelStyles: {
34
+ base: {
35
+ fontSize: '12px',
36
+ fontWeight: '500',
37
+ fontFamily: '"Inter", sans-serif'
38
+ },
39
+ },
40
+ errorTextStyles: {
41
+ base: {
42
+ fontSize: '12px',
43
+ fontWeight: '500',
44
+ color: "#f44336",
45
+ fontFamily: '"Inter", sans-serif'
46
+ },
47
+ },
48
+ labels: {
49
+ nameLabel: 'Titular de la tarjeta',
50
+ cardLabel: 'Número de tarjeta',
51
+ cvvLabel: 'CVC/CVV',
52
+ expiryDateLabel: 'Fecha de expiración',
53
+ },
54
+ placeholders: {
55
+ namePlaceholder: 'Nombre como aparece en la tarjeta',
56
+ cardPlaceholder: '1234 1234 1234 1234',
57
+ cvvPlaceholder: '3-4 dígitos',
58
+ expiryMonthPlaceholder: 'MM',
59
+ expiryYearPlaceholder: 'AA'
60
+ }
61
+ }
@@ -0,0 +1,112 @@
1
+ export const cardTemplate = `
2
+ <div class="container-tonder">
3
+ <div id="collectCardholderName" class="empty-div"></div>
4
+ <div id="collectCardNumber" class="empty-div"></div>
5
+ <div class="collect-row">
6
+ <div id="collectExpirationMonth" class="empty-div"></div>
7
+ <div id="collectExpirationYear" class="expiration-year"></div>
8
+ <div id="collectCvv" class="empty-div"></div>
9
+ </div>
10
+ <div id="msgError"></div>
11
+ <button id="tonderPayButton" class="pay-button">Pagar</button>
12
+ </div>
13
+
14
+ <style>
15
+ .container-tonder {
16
+ background-color: #F9F9F9;
17
+ margin: 0 auto !important;
18
+ padding: 30px 10px 30px 10px;
19
+ overflow: hidden;
20
+ transition: max-height 0.5s ease-out;
21
+ max-width: 600px;
22
+ border: solid 1px #e3e3e3;
23
+ max-height: 100vh;
24
+ }
25
+
26
+ .collect-row {
27
+ display: flex !important;
28
+ justify-content: space-between !important;
29
+ width: 100% !important;
30
+ }
31
+
32
+ .collect-row > :first-child {
33
+ min-width: 120px; !important
34
+ }
35
+
36
+ .expiration-year {
37
+ padding-top: 25px !important;
38
+ }
39
+
40
+ .empty-div {
41
+ height: 80px !important;
42
+ margin-top: 2px;
43
+ margin-bottom: 4px;
44
+ margin-left: 10px !important;
45
+ margin-right: 10px !important;
46
+ }
47
+
48
+ .error-container{
49
+ color: red !important;
50
+ background-color: #FFDBDB !important;
51
+ margin-bottom: 13px !important;
52
+ font-size: 80% !important;
53
+ padding: 8px 10px !important;
54
+ border-radius: 10px !important;
55
+ text-align: left !important;
56
+ }
57
+
58
+ .pay-button {
59
+ font-size: 16px;
60
+ font-weight: bold;
61
+ min-height: 2.3rem;
62
+ border-radius: 0.5rem;
63
+ cursor: pointer;
64
+ width: 100%;
65
+ padding: 1rem;
66
+ text-align: center;
67
+ border: none;
68
+ background-color: #000;
69
+ color: #fff;
70
+ margin-bottom: 10px;
71
+ display: none;
72
+ }
73
+
74
+ .lds-dual-ring {
75
+ display: inline-block;
76
+ width: 14px;
77
+ height: 14px;
78
+ }
79
+
80
+ .lds-dual-ring:after {
81
+ content: " ";
82
+ display: block;
83
+ width: 14px;
84
+ height: 14px;
85
+ border-radius: 50%;
86
+ border: 6px solid #fff;
87
+ border-color: #fff transparent #fff transparent;
88
+ animation: lds-dual-ring 1.2s linear infinite;
89
+ }
90
+ @keyframes lds-dual-ring {
91
+ 0% {
92
+ transform: rotate(0deg);
93
+ }
94
+ 100% {
95
+ transform: rotate(360deg);
96
+ }
97
+ }
98
+
99
+
100
+ @media screen and (max-width: 600px) {
101
+ .payment_method_zplit {
102
+ font-size: 16px !important;
103
+ width: 100% !important;
104
+ }
105
+
106
+ .payment_method_zplit label img {
107
+ display: none !important;
108
+ }
109
+ }
110
+
111
+ </style>
112
+ `
@@ -0,0 +1,68 @@
1
+ export async function addScripts() {
2
+ try {
3
+ const skyflowScript = document.createElement("script");
4
+ skyflowScript.src = "https://js.skyflow.com/v1/index.js";
5
+ await new Promise((resolve, reject) => {
6
+ skyflowScript.onload = resolve;
7
+ skyflowScript.onerror = reject;
8
+ document.head.appendChild(skyflowScript);
9
+ });
10
+
11
+ const openPay1Script = document.createElement("script");
12
+ openPay1Script.src = "https://openpay.s3.amazonaws.com/openpay.v1.min.js";
13
+ await new Promise((resolve, reject) => {
14
+ openPay1Script.onload = resolve;
15
+ openPay1Script.onerror = reject;
16
+ document.head.appendChild(openPay1Script);
17
+ });
18
+
19
+ const openPay2Script = document.createElement("script");
20
+ openPay2Script.src = "https://openpay.s3.amazonaws.com/openpay-data.v1.min.js";
21
+ await new Promise((resolve, reject) => {
22
+ openPay2Script.onload = resolve;
23
+ openPay2Script.onerror = reject;
24
+ document.head.appendChild(openPay2Script);
25
+ });
26
+
27
+ } catch (error) {
28
+ console.error("Error loading scripts", error);
29
+ }
30
+ }
31
+
32
+ export function toCurrency(value) {
33
+ if (isNaN(parseFloat(value))) {
34
+ return value;
35
+ }
36
+ var formatter = new Intl.NumberFormat("es-MX", {
37
+ style: "currency",
38
+ currency: "MXN",
39
+ minimumFractionDigits: 2
40
+ });
41
+ return formatter.format(value);
42
+ }
43
+
44
+ export function showError(message) {
45
+ var msgErrorDiv = document.getElementById("msgError");
46
+ msgErrorDiv.classList.add("error-container");
47
+ msgErrorDiv.innerHTML = message;
48
+ setTimeout(function () {
49
+ try {
50
+ document.querySelector("#tonderPayButton").disabled = false;
51
+ } catch (error) {}
52
+ msgErrorDiv.classList.remove("error-container");
53
+ msgErrorDiv.innerHTML = "";
54
+ }, 3000);
55
+ }
56
+
57
+ export function getBrowserInfo() {
58
+ const browserInfo = {
59
+ javascript_enabled: true, // Assumed since JavaScript is running
60
+ time_zone: new Date().getTimezoneOffset(),
61
+ language: navigator.language || 'en-US', // Fallback to 'en-US'
62
+ color_depth: window.screen ? window.screen.colorDepth : null,
63
+ screen_width: window.screen ? window.screen.width * window.devicePixelRatio || window.screen.width : null,
64
+ screen_height: window.screen ? window.screen.height * window.devicePixelRatio || window.screen.height : null,
65
+ user_agent: navigator.userAgent,
66
+ };
67
+ return browserInfo;
68
+ }
@@ -0,0 +1,129 @@
1
+ import { InlineCheckout } from './classes/inlineCheckout'
2
+
3
+ const customStyles = {
4
+ inputStyles: {
5
+ base: {
6
+ border: "2px dashed #4a90e2",
7
+ padding: "12px 8px",
8
+ borderRadius: "8px",
9
+ color: "#333333",
10
+ backgroundColor: "#f0f0f0",
11
+ fontFamily: '"Arial", sans-serif',
12
+ fontSize: '14px',
13
+ '&::placeholder': {
14
+ color: "#888888",
15
+ },
16
+ },
17
+ cardIcon: {
18
+ position: 'absolute',
19
+ left: '6px',
20
+ bottom: 'calc(50% - 12px)',
21
+ },
22
+ complete: {
23
+ color: "#4caf50",
24
+ },
25
+ empty: {},
26
+ focus: {},
27
+ invalid: {
28
+ border: "1px solid #f44336",
29
+ },
30
+ global: {
31
+ '@import': 'url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;700&display=swap")',
32
+ }
33
+ },
34
+ labelStyles: {
35
+ base: {
36
+ fontSize: '14px',
37
+ fontWeight: 'bold',
38
+ fontFamily: '"Inter", sans-serif',
39
+ color: "#4a90e2",
40
+ },
41
+ },
42
+ errorTextStyles: {
43
+ base: {
44
+ fontSize: '12px',
45
+ fontWeight: '500',
46
+ color: "#e74c3c",
47
+ fontFamily: '"Inter", sans-serif',
48
+ },
49
+ },
50
+ labels: {
51
+ nameLabel: 'Nombre de la de Tarjeta',
52
+ cardLabel: 'Número de Tarjeta',
53
+ cvvLabel: 'Código de Seguridad',
54
+ expiryDateLabel: 'Fecha de Expiración',
55
+ },
56
+ placeholders: {
57
+ namePlaceholder: 'Nombre como aparece en la tarjeta',
58
+ cardPlaceholder: '0000 0000 0000 0000',
59
+ cvvPlaceholder: '123',
60
+ expiryMonthPlaceholder: 'Mes',
61
+ expiryYearPlaceholder: 'Año'
62
+ }
63
+ }
64
+
65
+ const checkoutData = {
66
+ customer: {
67
+ firstName: "Adrian",
68
+ lastName: "Martinez",
69
+ country: "Mexico",
70
+ address: "Pinos 507, Col El Tecuan",
71
+ city: "Durango",
72
+ state: "Durango",
73
+ postCode: "34105",
74
+ email: "adrian@email.com",
75
+ phone: "8161234567",
76
+ },
77
+ currency: 'mxn',
78
+ cart: {
79
+ total: 399,
80
+ items: [
81
+ {
82
+ description: "Black T-Shirt",
83
+ quantity: 1,
84
+ price_unit: 1,
85
+ discount: 0,
86
+ taxes: 0,
87
+ product_reference: 1,
88
+ name: "T-Shirt",
89
+ amount_total: 399,
90
+ },
91
+ ]
92
+ },
93
+ card: { "skyflow_id": "53ca875c-16fd-4395-8ac9-c756613dbaf9" },
94
+ metadata: {
95
+ order_id: 123456
96
+ }
97
+ };
98
+
99
+ // localhost
100
+ const apiKey = "4c87c36e697e65ddfe288be0afbe7967ea0ab865";
101
+ const returnUrl = "http://127.0.0.1:8080/"
102
+ const successUrl = "http://127.0.0.1:8080/success"
103
+ // stage
104
+ // const apiKey = "8365683bdc33dd6d50fe2397188d79f1a6765852";
105
+
106
+ const inlineCheckout = new InlineCheckout({
107
+ apiKey,
108
+ returnUrl,
109
+ successUrl,
110
+ styles: customStyles
111
+ });
112
+
113
+ inlineCheckout.injectCheckout();
114
+
115
+ document.addEventListener('DOMContentLoaded', function() {
116
+ const payButton = document.getElementById('pay-button');
117
+ payButton.addEventListener('click', async function() {
118
+ try {
119
+ payButton.textContent = 'Procesando...';
120
+ const response = await inlineCheckout.payment(checkoutData);
121
+ console.log(response)
122
+ alert('Pago realizado con éxito');
123
+ } catch (error) {
124
+ alert('Error al realizar el pago')
125
+ } finally {
126
+ payButton.textContent = 'Pagar';
127
+ }
128
+ });
129
+ });
package/src/index.html ADDED
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <style>
8
+ #checkout-container {
9
+ display: flex;
10
+ justify-content: center;
11
+ }
12
+ #pay-button {
13
+ padding: 10px 20px;
14
+ margin-top: 30px;
15
+ background-color: #4a90e2;
16
+ color: white;
17
+ border: none;
18
+ border-radius: 5px;
19
+ font-size: 16px;
20
+ cursor: pointer;
21
+ transition: background-color 0.3s;
22
+ }
23
+ #payButton:hover {
24
+ background-color: #357abd;
25
+ }
26
+ .cart-details {
27
+ font-size: 3rem;
28
+ font-weight: bold;
29
+ padding: 2rem;
30
+ display: flex;
31
+ justify-content: center;
32
+ }
33
+ .button-container {
34
+ width: 100%;
35
+ display: flex;
36
+ justify-content: center;
37
+ }
38
+ </style>
39
+ </head>
40
+
41
+ <body>
42
+ <div class="checkout-container">
43
+ <div class="cart-details">
44
+ <span>Total&nbsp</span>
45
+ <div id="cart-total">$399</div>
46
+ </div>
47
+ <form id="payment-form">
48
+ <div id="tonder-checkout"></div>
49
+ </form>
50
+ <div class="button-container">
51
+ <button id="pay-button">Pagar</button>
52
+ </div>
53
+ </div>
54
+ </body>
55
+ <script src="https://js.skyflow.com/v1/index.js"></script>
56
+ <script src="https://openpay.s3.amazonaws.com/openpay.v1.min.js"></script>
57
+ <script src="https://openpay.s3.amazonaws.com/openpay-data.v1.min.js"></script>
58
+ </html>
package/src/index.js ADDED
@@ -0,0 +1,7 @@
1
+ import { Checkout } from './classes/checkout'
2
+ import { InlineCheckout } from './classes/inlineCheckout'
3
+
4
+ export {
5
+ Checkout,
6
+ InlineCheckout,
7
+ }
package/success.html ADDED
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html lang="es">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Pago Completado</title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ display: flex;
11
+ justify-content: center;
12
+ align-items: center;
13
+ height: 100vh;
14
+ margin: 0;
15
+ color: #333;
16
+ }
17
+ </style>
18
+ </head>
19
+ <body>
20
+ <h1>Pago completado con éxito</h1>
21
+ </body>
22
+ </html>