Skip to content

Commit

Permalink
Merge branch 'main' into development
Browse files Browse the repository at this point in the history
  • Loading branch information
David Hernandez committed Oct 22, 2024
2 parents aec714d + a93baf8 commit 3d920a5
Show file tree
Hide file tree
Showing 22 changed files with 533 additions and 26 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const paymentResponse = await liteCheckout.payment(paymentData);
|:---------:|:--------:|:--------------------------------------------------------------------------------------------:|
| mode | string | Environment mode. Options: 'stage', 'production', 'sandbox', 'development'. Default: 'stage' |
| apiKey | string | Your API key from the Tonder Dashboard |
| returnUrl | string | URL where the checkout form is mounted (used for 3DS) |
| returnrl | string | URL where the checkout form is mounted (used for 3DS) |
| callBack | function | Callback function to be invoked after the payment process ends successfully. |

## Mobile settings
Expand Down Expand Up @@ -431,10 +431,29 @@ export class TonderCheckoutComponent implements OnInit, OnDestroy {
}
```

## Request secure token

```typescript

const jsonResponse = await liteCheckout.getSecureToken(
secretApiKey //You can take this from you Tonder Dashboard
);

```

## Return secure token

```typescript
{
access: string;
}
```

## Deprecated Fields

The following fields have been deprecated and should no longer be used. Consider using the recommended alternatives:

## Register customer card
### `apiKeyTonder` Property

- **Deprecated Reason:** The `apiKeyTonder` property in the constructor and `IInlineLiteCheckoutOptions` interface is no longer required.
Expand Down
11 changes: 6 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tonder.io/ionic-lite-sdk",
"version": "0.0.35-beta.32",
"version": "0.0.42-beta.1",
"description": "Tonder ionic lite SDK",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -25,6 +25,7 @@
"@rollup/plugin-typescript": "11.1.6",
"@types/crypto-js": "^4.2.2",
"@types/jest": "^29.5.11",
"@types/lodash": "^4.17.10",
"@types/lodash.get": "^4.4.9",
"@types/node": "^20.11.5",
"jest": "^29.7.0",
Expand Down
114 changes: 112 additions & 2 deletions src/classes/3dsHandler.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,56 @@
import { CustomizationOptions } from "../types/commons"

type ThreeDSHandlerContructor = {
payload?: any,
apiKey?: string,
baseUrl?: string,
customization?: CustomizationOptions,
tdsIframeId?: string,
tonderPayButtonId?: string,
callBack?: (params: any) => any
}

export class ThreeDSHandler {

callBack?: (params: any) => any
baseUrl?: string
apiKey?: string
payload?: any
localStorageKey: string = "verify_transaction_status_url"
customization: CustomizationOptions = {
saveCards: {
showSaveCardOption: true,
showSaved: true,
autoSave: false
},
redirectOnComplete: true
}
tdsIframeId?: string
tonderPayButtonId?: string

constructor({
payload = null,
apiKey,
baseUrl,
customization,
tdsIframeId,
tonderPayButtonId,
callBack
}: ThreeDSHandlerContructor) {
this.baseUrl = baseUrl,
this.apiKey = apiKey,
this.payload = payload
this.tdsIframeId = tdsIframeId
this.tonderPayButtonId = tonderPayButtonId
this.customization = {
...this.customization,
...(customization || {}),
saveCards: {
...this.customization.saveCards,
...(customization?.saveCards || {}),
},
}
this.callBack = callBack
}

setStorageItem (data: any) {
Expand Down Expand Up @@ -128,10 +160,88 @@ export class ThreeDSHandler {
const url = this.getRedirectUrl()
if (url) {
this.saveVerifyTransactionUrl()
window.location = url;
if(this.customization) {
if(this.customization?.redirectOnComplete) {
window.location = url;
} else {
const iframe = document.querySelector(`#${this.tdsIframeId}`)
if(iframe) {

iframe.setAttribute("src", url);
iframe.setAttribute("style", "display: block");

const self = this;

const listenerHandler = async (event: any) => {

const checkStatus = (result: any) => result?.transaction_status !== "Pending";

const executeAction = () => {
try {
const selector: any = document.querySelector(`#${this.tonderPayButtonId}`);
if(selector) {
selector.disabled = false;
}
} catch {}
if(iframe) {
iframe.setAttribute("style", "display: none");
}
if(self.callBack) self.callBack(self.payload);
iframe.removeEventListener("load", listenerHandler);
}

const chainPromises = async (promise: Promise<any>) => {
const result = await new Promise((resolve, reject) => resolve(promise))
if(result) {
if(checkStatus(result)) {
return executeAction()
} else {
const timer = setTimeout(async () => {
clearTimeout(timer);
await chainPromises(self.requestTransactionStatus());
}, 7000)
}
}
}

await chainPromises(self.requestTransactionStatus())
}

iframe.addEventListener("load", listenerHandler)

} else {
console.log('No iframe found');
}
}
} else {
window.location = url;
}
} else {
if (this.callBack) this.callBack!(this.payload);
}
}

async requestTransactionStatus() {

const verifyUrl = this.getUrlWithExpiration();
const url = `${this.baseUrl}${verifyUrl}`;
const response = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Token ${this.apiKey}`,
},
// body: JSON.stringify(data),
});

if (response.status !== 200) {
console.error('La verificación de la transacción falló.');
return null;
} else {
console.log('No redirection found');
const response_json = await response.json();
return response_json;
}

}

// Returns an object
Expand Down
47 changes: 43 additions & 4 deletions src/classes/BaseInlineCheckout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
saveCustomerCard,
} from "../data/cardApi";
import { fetchCustomerPaymentMethods } from "../data/paymentMethodApi";
import {Business, IConfigureCheckout, IInlineCheckoutBaseOptions} from "../types/commons";
import {Business, IConfigureCheckout, IInlineCheckoutBaseOptions, CustomizationOptions} from "../types/commons";
import {ICustomer} from "../types/customer";
import {ICardFields, IItem, IProcessPaymentRequest, IStartCheckoutResponse} from "../types/checkout";
import {ICustomerCardsResponse, ISaveCardResponse, ISaveCardSkyflowRequest} from "../types/card";
Expand All @@ -31,11 +31,21 @@ export class BaseInlineCheckout {
mode?: "production" | "sandbox" | "stage" | "development" | undefined;
apiKeyTonder: string;
returnUrl?: string;
tdsIframeId?: string;
tonderPayButtonId?: string;
callBack?: ((response: IStartCheckoutResponse | Record<string, any>) => void) | undefined;
merchantData?: Business;
abortController: AbortController;

secureToken: string = "";
customer?: ICustomer | { email: string };
customization: CustomizationOptions = {
saveCards: {
showSaveCardOption: true,
showSaved: true,
autoSave: false
},
redirectOnComplete: true
}

cartItems?: IItem[];
metadata = {};
Expand All @@ -46,11 +56,14 @@ export class BaseInlineCheckout {

constructor({
mode = "stage",
customization,
apiKey,
apiKeyTonder,
returnUrl,
tdsIframeId,
callBack = () => {},
baseUrlTonder
baseUrlTonder,
tonderPayButtonId
}: IInlineCheckoutBaseOptions) {
this.apiKeyTonder = apiKeyTonder || apiKey || "";
this.returnUrl = returnUrl;
Expand All @@ -62,11 +75,25 @@ export class BaseInlineCheckout {
this.process3ds = new ThreeDSHandler({
apiKey: apiKey,
baseUrl: this.baseUrl,
customization: customization,
tdsIframeId: tdsIframeId,
tonderPayButtonId: tonderPayButtonId,
callBack: callBack
});
this.tdsIframeId = tdsIframeId;
this.customization = {
...this.customization,
...(customization || {}),
saveCards: {
...this.customization.saveCards,
...(customization?.saveCards || {})
}
}
}

configureCheckout(data: IConfigureCheckout) {
if ("customer" in data) this.#handleCustomer(data["customer"]);
if ("secureToken" in data) this.#setSecureToken(data["secureToken"]);
}

async verify3dsTransaction(): Promise<ITransaction | IStartCheckoutResponse | void> {
Expand All @@ -87,9 +114,15 @@ export class BaseInlineCheckout {
this.#handleCard(data);
const response = await this._checkout(data);
this.process3ds.setPayload(response);
if (this.callBack) this.callBack!(response);
const payload = await this._handle3dsRedirect(response);
if (payload) {
try {
const selector: any = document.querySelector(`#${this.tonderPayButtonId}`);
if(selector) {
selector.disabled = false;
}
} catch {}
if (this.callBack) this.callBack!(response);
resolve(response);
}
} catch (error) {
Expand Down Expand Up @@ -272,11 +305,13 @@ export class BaseInlineCheckout {

async _saveCustomerCard(
authToken: string,
secureToken: string,
businessId: string | number,
skyflowTokens: ISaveCardSkyflowRequest,
): Promise<ISaveCardResponse> {
return await saveCustomerCard(
this.baseUrl,
this.secureToken,
authToken,
businessId,
skyflowTokens,
Expand Down Expand Up @@ -305,6 +340,10 @@ export class BaseInlineCheckout {
this.customer = customer;
}

#setSecureToken(token: string) {
this.secureToken = token;
}

#setCartItems(items: IItem[]) {
this.cartItems = items;
}
Expand Down
Loading

0 comments on commit 3d920a5

Please sign in to comment.