invoiceninja/resources/js/clients/payments/powerboard-credit-card.js
2024-09-26 13:48:28 +10:00

322 lines
9.6 KiB
JavaScript
Vendored

/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
import { instant, wait } from '../wait';
let focusCreditCard = false;
function setup() {
const publicKey = document.querySelector('meta[name=public_key]');
const gatewayId = document.querySelector('meta[name=gateway_id]');
const env = document.querySelector('meta[name=environment]');
const supportedCards = document.querySelector('meta[name=supported_cards]');
const widget = new cba.HtmlWidget(
'#widget',
publicKey?.content,
gatewayId?.content
);
widget.setEnv(env?.content);
widget.useAutoResize();
if (supportedCards?.content) {
try {
const supportedCardsArray = JSON.parse(supportedCards.content);
widget.setSupportedCardIcons(supportedCardsArray, true);
} catch (error) {
}
}
widget.interceptSubmitForm('#stepone');
widget.onFinishInsert(
'#server-response input[name="gateway_response"]',
'payment_source'
);
widget.setFormFields(['card_name*']);
widget.reload();
let payNow = document.getElementById('pay-now');
payNow.disabled = false;
payNow.querySelector('svg').classList.add('hidden');
payNow.querySelector('span').classList.remove('hidden');
document.querySelector(
'#server-response input[name="gateway_response"]'
).value = '';
return widget;
}
function reload() {
document.querySelector('#widget')?.replaceChildren();
document.querySelector('#widget')?.classList.remove('hidden');
document.querySelector('#widget-3dsecure')?.replaceChildren();
}
function pay() {
reload();
const gatewayId = document.querySelector('meta[name=gateway_id]')?.content;
if(!gatewayId) {
let payNow = document.getElementById('pay-now');
payNow.disabled = true;
payNow.querySelector('svg').classList.remove('hidden');
payNow.querySelector('span').classList.add('hidden');
document.getElementById(
'errors'
).textContent = 'Gateway not found or verified';
document.getElementById('errors').hidden = false;
}
const widget = setup();
widget.on('finish', () => {
document.getElementById('errors').hidden = true;
process3ds();
});
widget.on('submit', function (data) {
document.getElementById('errors').hidden = true;
});
let payNow = document.getElementById('pay-now');
payNow.addEventListener('click', () => {
const div = document.getElementById('widget');
widget.getValidationState();
if (!widget.isValidForm() && div.offsetParent !== null) {
payNow.disabled = false;
payNow.querySelector('svg').classList.add('hidden');
payNow.querySelector('span').classList.remove('hidden');
return;
}
payNow.disabled = true;
payNow.querySelector('svg').classList.remove('hidden');
payNow.querySelector('span').classList.add('hidden');
let storeCard = document.querySelector(
'input[name=token-billing-checkbox]:checked'
);
if (storeCard) {
document.getElementById('store_card').value = storeCard.value;
}
if (div.offsetParent !== null)
document.getElementById('stepone_submit').click();
else document.getElementById('server-response').submit();
});
document
.getElementById('toggle-payment-with-credit-card')
.addEventListener('click', (element) => {
let widget = document.getElementById('widget');
widget.classList.remove('hidden');
document.getElementById('save-card--container').style.display =
'grid';
document.querySelector('input[name=token]').value = '';
document
.querySelector('#powerboard-payment-container')
?.classList.remove('hidden');
});
Array.from(
document.getElementsByClassName('toggle-payment-with-token')
).forEach((element) =>
element.addEventListener('click', (element) => {
document.getElementById('widget').classList.add('hidden');
document.getElementById('save-card--container').style.display =
'none';
document.querySelector('input[name=token]').value =
element.target.dataset.token;
document
.querySelector('#powerboard-payment-container')
?.classList.add('hidden');
})
);
const first = document.querySelector('input[name="payment-type"]');
if (first) {
first.click();
}
if (focusCreditCard) {
document.getElementById('toggle-payment-with-credit-card')?.click();
}
}
async function process3ds() {
try {
const resource = await get3dsToken();
if (
!resource ||
!resource.status ||
resource.status === 'not_authenticated' ||
resource === 'not_authenticated'
) {
focusCreditCard = true;
pay();
throw new Error(
'There was an issue authenticating this payment method.'
);
}
if (resource.status === 'authentication_not_supported') {
document.querySelector('input[name="browser_details"]').value =
null;
document.querySelector('input[name="charge"]').value =
JSON.stringify(resource);
let storeCard = document.querySelector(
'input[name=token-billing-checkbox]:checked'
);
if (storeCard) {
document.getElementById('store_card').value = storeCard.value;
}
return document.getElementById('server-response').submit();
}
const canvas = new cba.Canvas3ds(
'#widget-3dsecure',
resource._3ds.token
);
canvas.load();
let widget = document.getElementById('widget');
widget.classList.add('hidden');
canvas.on('chargeAuthSuccess', function (data) {
document.querySelector('input[name="browser_details"]').value =
null;
document.querySelector('input[name="charge"]').value =
JSON.stringify(data);
let storeCard = document.querySelector(
'input[name=token-billing-checkbox]:checked'
);
if (storeCard) {
document.getElementById('store_card').value = storeCard.value;
}
document.getElementById('server-response').submit();
});
canvas.on('chargeAuthReject', function (data) {
document.getElementById(
'errors'
).textContent = `Sorry, your transaction could not be processed...`;
document.getElementById('errors').hidden = false;
focusCreditCard = true;
pay();
});
canvas.load();
} catch (error) {
const msg = error.message ?? 'Unknown error.';
document.getElementById(
'errors'
).textContent = `Sorry, your transaction could not be processed...\n\n${msg}`;
document.getElementById('errors').hidden = false;
focusCreditCard = true;
pay();
}
}
async function get3dsToken() {
const browserDetails = {
name: navigator.userAgent.substring(0, 100), // The full user agent string, which contains the browser name and version
java_enabled: navigator.javaEnabled() ? 'true' : 'false', // Indicates if Java is enabled in the browser
language: navigator.language || navigator.userLanguage, // The browser language
screen_height: window.screen.height.toString(), // Screen height in pixels
screen_width: window.screen.width.toString(), // Screen width in pixels
time_zone: (new Date().getTimezoneOffset() * -1).toString(), // Timezone offset in minutes (negative for behind UTC)
color_depth: window.screen.colorDepth.toString(), // Color depth in bits per pixel
};
document.querySelector('input[name="browser_details"]').value =
JSON.stringify(browserDetails);
const formData = JSON.stringify(
Object.fromEntries(
new FormData(document.getElementById('server-response'))
)
);
const paymentsRoute = document.querySelector('meta[name=payments_route]');
try {
// Return the fetch promise to handle it externally
const response = await fetch(paymentsRoute.content, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
Accept: 'application/json',
'X-CSRF-Token': document.querySelector(
'meta[name="csrf-token"]'
).content,
},
body: formData,
});
if (!response.ok) {
return await response.json().then((errorData) => {
throw new Error(errorData.message ?? 'Unknown error.');
});
}
return await response.json();
} catch (error) {
document.getElementById(
'errors'
).textContent = `Sorry, your transaction could not be processed...\n\n${error.message}`;
document.getElementById('errors').hidden = false;
focusCreditCard = true;
pay();
}
}
instant() ? pay() : wait('#powerboard-credit-card-payment').then(() => pay());