sprinque-js-sdk-wip
Version:
UI kit to implement Pay by Invoice with Sprinque
2,174 lines • 81 kB
JavaScript
import * as FullStory from '@fullstory/browser';
import i18next from 'i18next';
import { checkRegNumber } from 'b2b-sprinque-tools';
import intlTelInput from 'intl-tel-input';
const SPRINQUE_CUSTOM_ELEMENT_NAME = 'sprinque-modal';
const SPRINQUE_STEP_CLASS = 'sprinque-step';
const VALIDATION_ERROR_CLASS_PREFIX = 'validation-error-';
const CUSTOM_NAVIGATION_EVENT = 'sprinque-to-step';
// session storage
const MERCHANT_BUYER_ID = 'sp-merchant-buyer-id';
const BUYER_ID = 'sp-buyer-id';
const FALLBACK_LOGO_URL = 'https://d2f2ha363kdzm.cloudfront.net/sprinque-logo-dark-blue.png';
const FALLBACK_ADDRESS = {
address_line1: 'Nieuwezijds Voorburgwal 296 102',
address_line2: '',
city: 'AMSTERDAM',
country: 'NL',
zip_code: '1012RT'
};
const SUPPORTED_NET_TERMS = ['net7', 'net15', 'net30', 'net45', 'net60', 'net90'];
const API_ERROR_ELEM = '.validation-error-from-api';
// step 1
const COUNTRY_SELECT = '#sp-country';
const COMPANY_NAME = '#sp-company-name';
const SEARCH_TYPE = '#search-type';
const SEARCH_BY_NAME = '#search-type-by-name';
const SEARCH_BY_VAT = '#search-type-by-vat';
const REG_NUMBER = '#sp-reg-number';
const REG_NUMBER_ASTERISK = '#sp-reg-number-asterisk';
const BILLING_EMAIL = '#billing-email';
const REG_NUMBER_WARNING = '#reg-number-warning';
const STEP_1_NEXT_BTN = '#sp-form-step-1 .nav';
// step 2
const ADDRESS_LINE_1 = '#sp-address-line1';
const ADDRESS_LINE_2 = '#sp-address-line2';
const ADDRESS_CITY = '#sp-address-city';
const ADDRESS_ZIP = '#sp-address-zip';
// step 3
const USER_NAME = '#sp-user-name';
const USER_SURNAME = '#sp-user-surname';
const USER_EMAIL = '#sp-user-email';
const USER_PHONE = '#sp-user-phone';
// step 4
const USER_EMAIL_TO = '#otp-email-to';
const OTP_DIGIT = '.sp-otp-digit';
// step 5
const ORDER_TOTAL_CURRENCY = '#order-total-currency';
const ORDER_TOTAL_AMOUNT = '#order-total-amount';
const removeSprinqueModal = () => {
const element = document.getElementsByTagName('sprinque-modal')[0];
if (element) element.remove();
};
const registerModalBgListener = shadowRoot => {
const modalWrapper = shadowRoot.querySelector('.sprinque-modal-wrapper');
if (modalWrapper) modalWrapper.addEventListener('click', removeSprinqueModal);
// close by icon
const closeBtn = shadowRoot.querySelector('.close-btn');
if (closeBtn) closeBtn.addEventListener('click', removeSprinqueModal);
// stop modal propagation
const modal = shadowRoot.querySelector('.sprinque-modal');
if (modal) modal.addEventListener('click', e => e.stopPropagation());
};
const showNextStep = (shadowRoot, currentStep, nextStep) => {
const currentElement = shadowRoot.querySelector(`.${SPRINQUE_STEP_CLASS}-${currentStep}`);
const nextElement = shadowRoot.querySelector(`.${SPRINQUE_STEP_CLASS}-${nextStep}`);
currentElement.style.display = 'none';
nextElement.style.display = 'block';
};
const debounce = callback => {
// @ts-ignore
let timeout;
return value => {
// @ts-ignore
clearTimeout(timeout);
timeout = setTimeout(() => callback(value), 500);
};
};
const onSelectBusiness = (
// @ts-ignore
shadowRoot, name, address, regNumber, creditBureauId) => {
// set business name
if (name) shadowRoot.getElementById(COMPANY_NAME.replace('#', '')).value = name;
// set credit bureau id from search
if (creditBureauId) shadowRoot.getElementById(COMPANY_NAME.replace('#', '')).dataset.creditBureauId = creditBureauId;
// set reg number
if (regNumber) shadowRoot.getElementById('sp-reg-number').value = regNumber;
// set address
if (address) {
try {
const {
address_line_1,
address_line_2,
city,
zipcode
} = JSON.parse(address);
if (address_line_1) shadowRoot.getElementById('sp-address-line1').value = address_line_1;
if (address_line_2) shadowRoot.getElementById('sp-address-line2').value = address_line_2;
if (city) shadowRoot.getElementById('sp-address-city').value = city;
if (zipcode) shadowRoot.getElementById('sp-address-zip').value = zipcode;
} catch (e) {
console.log(`Sprinque > failed to parse address for ${name}`);
}
}
// clear search results
shadowRoot.getElementById('sprinque-businesses').innerHTML = '';
};
const getElemValueBySelector = (selector, shadowRoot) => shadowRoot.querySelector(selector).value;
const displayCorrectLabelForBusinessSearch = (searchByVat, shadowRoot) => {
const isSearchByVat = searchByVat === 'true';
shadowRoot.getElementById(SEARCH_TYPE.replace('#', '')).style.display = isSearchByVat ? 'inline-flex' : 'none';
shadowRoot.querySelector(`[for=${COMPANY_NAME.replace('#', '')}]`).style.display = isSearchByVat ? 'none' : 'block';
};
const displayApiError = (message, shadowRoot) => {
const elem = shadowRoot.querySelector(API_ERROR_ELEM);
elem.style.display = 'block';
elem.innerHTML = message;
// hide after 10 sec
setTimeout(() => {
elem.style.display = 'none';
}, 10 * 1000);
};
const parseSpinqueErrorResponse = response => {
if (!response || !response.errors) return 'Failed to parse backend error';
let errorsString = '';
Object.entries(response.errors).forEach(([key, valArr]) => errorsString += `${key} > ${valArr.join(', ')} `);
return errorsString;
};
const getApiUrl = () => {
var _a;
const env = (_a = document.querySelector(SPRINQUE_CUSTOM_ELEMENT_NAME)) === null || _a === void 0 ? void 0 : _a.getAttribute('env');
const envToApiUrlMap = {
testing: 'https://api-testing.sprinque.com/api/v1/',
production: 'https://api.sprinque.com/api/v1/',
sandbox: 'https://api-sandbox.sprinque.com/api/v1/'
};
// @ts-ignore
return envToApiUrlMap[env];
};
const MAX_RETRY = 3;
let current = 0;
const request = async (url, shadowRoot, data, method = 'POST') => {
// show loader
const loader = shadowRoot.querySelector(`[class^=${SPRINQUE_STEP_CLASS}]:not([style*="display: none"]) .sprinque-ellipsis`);
if (loader) loader.style.display = 'block';
// get token
const rootHtmlElem = document.querySelector(SPRINQUE_CUSTOM_ELEMENT_NAME);
const token = rootHtmlElem === null || rootHtmlElem === void 0 ? void 0 : rootHtmlElem.getAttribute('token');
// execute call
const response = await fetch(getApiUrl() + url, {
method,
body: JSON.stringify(data),
headers: {
'Content-type': 'application/json; charset=UTF-8',
//'X-API-KEY-ID': token,
'X-Authorization': `Bearer ${token}`
}
});
// handle results
const resp = await response.json();
if (loader) loader.style.display = 'none';
// handle failure
if (!response.ok) {
const apiResp = await resp;
displayApiError(parseSpinqueErrorResponse(apiResp), shadowRoot);
const getTokenUrl = rootHtmlElem === null || rootHtmlElem === void 0 ? void 0 : rootHtmlElem.getAttribute('getTokenUrl');
// 401
if (response.status === 401 && current < MAX_RETRY) {
current += 1;
if (getTokenUrl) {
// fetch temporary token
const resp = await fetch(`${getTokenUrl}`);
const {
access
} = await resp.json();
if (access) {
rootHtmlElem === null || rootHtmlElem === void 0 ? void 0 : rootHtmlElem.setAttribute('token', access);
// try to do re-fetch
return request(url, shadowRoot, data, method);
}
} else {
displayApiError('Session expired', shadowRoot);
}
}
}
return resp;
};
const FORM_ELEM_COLOR = '#6266A7';
const ACTIVE_ITEM_COLOR = '#000339';
const DISABLED_COLOR = '#B6B8E2';
const LIGHT_COLOR = '#fff';
const BORDER_COLOR = '#e8e4e4';
const ERROR_COLOR = '#ee3f75';
const MAIN_STYLES = `
<style>
:host * {
font-size: 14px;
}
:host h3, :host span, :host div {
color: ${ACTIVE_ITEM_COLOR};
}
:host h3 {
font-size: 20px;
}
:host p {
margin: 0;
}
/*main*/
.sprinque-modal-wrapper {
position: fixed;
z-index: 9999;
left: 0;
top: 0;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, .5);
display: flex;
justify-content: center;
align-items: center;
}
.sprinque-modal {
position: relative;
font-family: sans-serif;
background: ${LIGHT_COLOR};
width: 400px;
display: grid;
grid-template-columns: 1fr;
margin-bottom: 10px;
padding: 20px;
border-radius: 10px;
max-width: 90%;
}
.sprinque-header {
display: flex;
align-items: baseline;
justify-content: space-between;
}
.sprinque-stepper {
color: ${ACTIVE_ITEM_COLOR};
font-weight: bold;
white-space: nowrap;
font-size: 16px;
}
.sprinque-api-error {
background: ${ERROR_COLOR};
color: ${LIGHT_COLOR};
padding: 4px;
font-size: 14px;
}
.close-btn {
font-size: 26px;
cursor: pointer;
font-weight: 100;
color: ${ACTIVE_ITEM_COLOR};
position: absolute;
right: 20px;
top: 20px;
}
/* logo */
.sprinque-logo-wrapper {
text-align: center;
min-height: 50px;
}
.sprinque-logo {
max-width: 200px;
max-height: 50px;
}
/* form */
label {
display: block;
font-weight: bold;
color: ${FORM_ELEM_COLOR};
margin-top: 20px;
padding: 5px 0;
}
.sprinque-modal label span {color: ${FORM_ELEM_COLOR};}
input, select {
display: block;
border: 1px solid ${DISABLED_COLOR};
border-radius: 4px;
width: calc(100% - 20px);
font-size: 16px;
padding: 8px 10px;
}
input:active, input:focus, select:focus {
border-color: ${ACTIVE_ITEM_COLOR};
color: ${ACTIVE_ITEM_COLOR};
outline: none;
}
select {
width: 100%;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAPCAYAAAARZmTlAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADqSURBVHgBpdHNDYIwFAfw1yfx7AiMoHEB3cELXqwmuoa4gWc00BsnD04gCxhX6ByGFFuCiamltPBPCP14fb8mJSBDaTaBIJhCGXDGIg4Do/cjlOYhjuEh90L5cfGG5RDI1A9xLGizoFIXqELoEQ1o+gmKQmCh1faCDEAdUSFHdo0KOT4NgdoA1ZddIka+s90hj+XvqBV1vpENSJMoVgPyu+oLuQB/iA/kChgRF8gHaEWskCi3iEHmClgRC2RKK6AyAktez1sxm6/URRZ9gU7EAeoEnBAL5ASoEPAI3edUHtgQUt3TZH12PfcBJLGTJFbnlZQAAAAASUVORK5CYII=') no-repeat 97% 50%;
background-size: 12px 7px;
}
/* powered by */
.sprinque-powered-img {
height: 16px;
margin-bottom: -4px;
opacity: 0.3
}
.powered-by {
margin-top: 10px;
color: ${DISABLED_COLOR};
display: flex;
justify-content: space-between;
}
.powered-by div {
color: ${DISABLED_COLOR};
}
/* buttons */
button {
color: ${LIGHT_COLOR};
background: ${ACTIVE_ITEM_COLOR};
border: 2px solid ${ACTIVE_ITEM_COLOR};
border-radius: 4px;
transition: .3s;
font-weight: bold;
font-size: 16px;
padding: 8px 20px;
margin: 10px 0;
cursor: pointer;
}
button:disabled, button:disabled:hover {
background: ${DISABLED_COLOR};
border-color: ${DISABLED_COLOR};
}
button:hover {
background: ${FORM_ELEM_COLOR};
}
button.secondary {
border: 2px solid ${ACTIVE_ITEM_COLOR};
background: transparent;
color: ${ACTIVE_ITEM_COLOR};
}
button.secondary:hover {
background: ${BORDER_COLOR};
}
button.secondary.sp-arrow {
border-color: ${ACTIVE_ITEM_COLOR};
}
button.secondary .sp-arrow {
border-color: ${ACTIVE_ITEM_COLOR};
}
button.secondary .sp-arrow::before {
background: ${ACTIVE_ITEM_COLOR};
}
/* common */
.sprinque-text-right {
text-align: right;
}
.cursour-pointer {
cursor: pointer;
}
.justify-between {
display: flex;
justify-content: space-between;
}
/* validation */
div[class^="${VALIDATION_ERROR_CLASS_PREFIX}"] {
color: ${ERROR_COLOR};
font-weight: bold;
}
.warning {
background: rgb(255, 244, 229);
padding: 10px;
color: rgb(102, 60, 0);
border-radius: 4px;
border: 1px solid ${BORDER_COLOR};
}
.sp-arrow {
border: solid white;
border-width: 0 2px 2px 0;
display: inline-block;
padding: 4px;
}
.sp-arrow::before {
content: "";
width: 14px;
height: 2px;
background: white;
position: absolute;
rotate: 45deg;
top: 3px;
right: -3px;
}
.sp-right {
margin-left: 10px;
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.sp-left {
margin-right: 10px;
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
}
</style>
`;
let itiPhoneInput;
const registerStep2Listeners = shadowRoot => {
// on next step
shadowRoot.addEventListener(`${CUSTOM_NAVIGATION_EVENT}3`, async () => {
var _a;
// set phone mask
const phoneInput = shadowRoot.querySelector(USER_PHONE);
const countryCode = ((_a = shadowRoot.querySelector(COUNTRY_SELECT)) === null || _a === void 0 ? void 0 : _a.value) || 'nl';
itiPhoneInput = intlTelInput(phoneInput, {
initialCountry: countryCode.toLowerCase(),
preferredCountries: ['nl', 'de', 'es', 'fr', 'be'],
autoPlaceholder: 'aggressive',
utilsScript: 'https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.21/js/utils.min.js'
});
});
};
const EMAIL_REG = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const checkIfFieldIsValid = (type, selector, shadowRoot) => {
const elem = shadowRoot.querySelector(selector);
const validationRule = {
requiredFields: Boolean(elem.value),
emails: elem.value.match(EMAIL_REG),
phones: (itiPhoneInput === null || itiPhoneInput === void 0 ? void 0 : itiPhoneInput.isValidNumber()) || false
};
const isValid = validationRule[type];
elem.style.borderColor = isValid ? BORDER_COLOR : ERROR_COLOR;
return isValid;
};
const getPhoneErrorMessage = itiPhoneInput => {
var _a, _b, _c;
if (!itiPhoneInput || !window.intlTelInputUtils) return '';
const error = itiPhoneInput.getValidationError();
if (error === ((_a = intlTelInputUtils === null || intlTelInputUtils === void 0 ? void 0 : intlTelInputUtils.validationError) === null || _a === void 0 ? void 0 : _a.INVALID_COUNTRY_CODE)) {
return i18next.t('validation.invalidCountryCode');
}
if (error === ((_b = intlTelInputUtils === null || intlTelInputUtils === void 0 ? void 0 : intlTelInputUtils.validationError) === null || _b === void 0 ? void 0 : _b.TOO_SHORT)) {
return i18next.t('validation.phoneIsShort');
}
if (error == ((_c = intlTelInputUtils === null || intlTelInputUtils === void 0 ? void 0 : intlTelInputUtils.validationError) === null || _c === void 0 ? void 0 : _c.TOO_LONG)) {
return i18next.t('validation.phoneIsLong');
}
return i18next.t('validation.invalidPhone');
};
const getValidationMessage = fieldType => {
switch (fieldType) {
case 'requiredFields':
return i18next.t('validation.fillAllFields');
case 'emails':
return i18next.t('validation.invalidEmail');
case 'phones':
return getPhoneErrorMessage(itiPhoneInput);
default:
return 'Unknown validation error';
}
};
const getValidationConfig = isRegNumberRequired => ({
'1': {
requiredFields: isRegNumberRequired ? [REG_NUMBER, BILLING_EMAIL] : [BILLING_EMAIL],
emails: [BILLING_EMAIL]
},
'2': {
requiredFields: [ADDRESS_LINE_1,
//'#sp-address-line2',
'#sp-address-city', '#sp-address-zip']
},
'3': {
requiredFields: ['#sp-user-name', '#sp-user-surname', USER_EMAIL, USER_PHONE],
emails: [USER_EMAIL],
phones: [USER_PHONE]
},
'4': {},
'5': {},
'6': {}
});
const checkIfRegNumberIsRequired = shadowRoot => {
var _a, _b;
const selectedCountryValue = (_a = shadowRoot.querySelector(COUNTRY_SELECT)) === null || _a === void 0 ? void 0 : _a.value;
const option = shadowRoot.querySelector(`#country-${selectedCountryValue}`);
if (!option || !selectedCountryValue) return true;
return ((_b = option === null || option === void 0 ? void 0 : option.dataset) === null || _b === void 0 ? void 0 : _b.isRegNumberRequired) === 'true';
};
const isValidStep = (step, shadowRoot) => {
let isValid = true;
const isRegNumberRequired = checkIfRegNumberIsRequired(shadowRoot);
// iterate validation types "requiredFields", "emails"...
for (const [validationType, selectors] of Object.entries(getValidationConfig(isRegNumberRequired)[step])) {
// iterate each input
const error = selectors.find(selector => !checkIfFieldIsValid(validationType, selector, shadowRoot));
if (error) {
isValid = false;
showValidationError(step, validationType, shadowRoot);
break;
}
}
if (isValid) hideValidationError(step, shadowRoot);
return isValid;
};
const showValidationError = (step, validationType, shadowRoot) => {
shadowRoot.querySelector(`.${VALIDATION_ERROR_CLASS_PREFIX}${step}`).innerHTML = getValidationMessage(validationType);
};
const hideValidationError = (step, shadowRoot) => {
shadowRoot.querySelector(`.${VALIDATION_ERROR_CLASS_PREFIX}${step}`).innerHTML = '';
};
const getSearchItemLayout = ({
business_name,
registration_number,
address,
credit_bureau_id
}) => `
<div
class='sprinque-businesses-item cursour-pointer'
data-name='${business_name}'
data-reg='${registration_number}'
data-creditBureauId='${credit_bureau_id}'
data-address='${JSON.stringify(address)}'
>
<b>${business_name}</b><br/>
<small>${Object.values(address).filter(item => item).join(', ')}</small><br/>
<small>${registration_number}</small>
</div>
`;
const getSearchNotFoundItemLayout = () => `
<div class='sprinque-businesses-item cursour-pointer'>
<b>${i18next.t('business.cantFind')}</b><br/>
<small>${i18next.t('business.cantFindInstruction')}</small><br/>
</div>
`;
const setIpAndLocationData = async (shadowRoot, buyerId) => {
var _a, _b;
// fetch IP address (used https://stackoverflow.com/a/35123097/6082084)
const response = await fetch('https://api.db-ip.com/v2/free/self', {
method: 'GET'
});
const {
ipAddress,
continentCode,
continentName,
countryCode,
countryName,
city
} = await response.json();
const companyNameInput = shadowRoot.querySelector(COMPANY_NAME);
if (ipAddress) {
companyNameInput.dataset.ipv4 = ipAddress;
}
if (continentCode) {
companyNameInput.dataset.continentCode = continentCode;
}
if (continentName) {
companyNameInput.dataset.continentName = continentName;
}
if (countryCode) {
companyNameInput.dataset.countryCode = countryCode;
// if buyerId is not provided - preselect country by IP.
const countryIsSupported = shadowRoot.querySelector(`#country-${countryCode}`);
if (!buyerId && countryIsSupported) {
// set country
shadowRoot.querySelector(COUNTRY_SELECT).value = countryCode;
// enable company name and reg number inputs
(_a = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(COMPANY_NAME)) === null || _a === void 0 ? void 0 : _a.removeAttribute('disabled');
(_b = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(REG_NUMBER)) === null || _b === void 0 ? void 0 : _b.removeAttribute('disabled');
// set reg number as required if needed
const isRegNumberRequired = checkIfRegNumberIsRequired(shadowRoot);
const regNumberAsterisk = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(REG_NUMBER_ASTERISK);
regNumberAsterisk.innerHTML = isRegNumberRequired ? '*' : '';
}
}
if (countryName) {
companyNameInput.dataset.countryName = countryName;
}
if (city) {
companyNameInput.dataset.city = city;
}
};
const registerStep1Listeners = async (shadowRoot, lang, buyerId) => {
const companyNameInput = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.getElementById(COMPANY_NAME.replace('#', ''));
const nextBtn = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(STEP_1_NEXT_BTN);
const businessesDiv = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.getElementById('sprinque-businesses');
const countrySelect = shadowRoot.getElementById(COUNTRY_SELECT.replace('#', ''));
const regNumberInput = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(REG_NUMBER);
// fetch supported countries
const countries = await request('countries/', shadowRoot, undefined, 'GET');
if (!Array.isArray(countries)) return;
// insert countries to html options
countrySelect.innerHTML = `<option value="" selected disabled>${i18next.t('business.selectCountry')}</option>`;
countries.filter(country => country.status === 'ACTIVE').sort((a, b) => a.code < b.code ? -1 : 1).forEach(country => {
countrySelect.innerHTML += `<option
id="country-${country.code}"
value="${country.code}"
data-search-by-vat="${country.is_search_by_vat_available}"
data-is-reg-number-required='${country.is_registration_number_required}'>
${country.name}
</option>`;
});
// on change country
if (countrySelect) {
countrySelect.addEventListener('change', event => {
var _a;
(_a = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(COMPANY_NAME)) === null || _a === void 0 ? void 0 : _a.removeAttribute('disabled');
regNumberInput === null || regNumberInput === void 0 ? void 0 : regNumberInput.removeAttribute('disabled');
// toggle "search by" type
// @ts-ignore
const {
searchByVat
} = event.target.options[event.target.selectedIndex].dataset;
displayCorrectLabelForBusinessSearch(searchByVat, shadowRoot);
// set reg number asterisk for required case
// @ts-ignore
const {
isRegNumberRequired
} = event.target.options[event.target.selectedIndex].dataset;
const regNumberAsterisk = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(REG_NUMBER_ASTERISK);
regNumberAsterisk.innerHTML = isRegNumberRequired === 'true' ? '*' : '';
// reset company name
companyNameInput.value = '';
nextBtn === null || nextBtn === void 0 ? void 0 : nextBtn.setAttribute('disabled', 'true');
if (businessesDiv) businessesDiv.innerHTML = '';
});
}
// fetch IP and location data and set it to the form
await setIpAndLocationData(shadowRoot, buyerId);
// toggle "search by" type
const searchByNameSelector = SEARCH_BY_NAME.replace('#', '');
const searchByVatSelector = SEARCH_BY_VAT.replace('#', '');
const searchByNameCheckbox = shadowRoot.getElementById(searchByNameSelector);
const searchByVatCheckbox = shadowRoot.getElementById(searchByVatSelector);
// search by name
if (searchByNameCheckbox) {
searchByNameCheckbox.addEventListener('change', e => {
var _a;
// @ts-ignore
if ((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.checked) {
shadowRoot.getElementById(SEARCH_TYPE.replace('#', '')).dataset.searchBy = 'NAME';
shadowRoot.getElementById(searchByVatSelector).checked = false;
}
});
}
// search by vat
if (searchByVatCheckbox) {
searchByVatCheckbox.addEventListener('change', e => {
var _a;
// @ts-ignore
if ((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.checked) {
shadowRoot.getElementById(SEARCH_TYPE.replace('#', '')).dataset.searchBy = 'VAT_ID';
shadowRoot.getElementById(searchByNameSelector).checked = false;
}
});
}
// on company name change
// @ts-ignore
const onInputCompanyName = async (value = '') => {
var _a, _b;
if (value) {
// enable next button
nextBtn === null || nextBtn === void 0 ? void 0 : nextBtn.removeAttribute('disabled');
} else {
// disable next button
nextBtn === null || nextBtn === void 0 ? void 0 : nextBtn.setAttribute('disabled', 'true');
}
const {
businesses = []
} = await request('search/business', shadowRoot, {
search_type: (_a = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.getElementById(SEARCH_TYPE.replace('#', ''))) === null || _a === void 0 ? void 0 : _a.dataset.searchBy,
search_term: value,
country_code: (_b = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.getElementById(COUNTRY_SELECT.replace('#', ''))) === null || _b === void 0 ? void 0 : _b.value
});
// insert business company matches
if (businessesDiv) {
let options = getSearchNotFoundItemLayout();
businesses.forEach(({
business_name,
registration_number,
address = FALLBACK_ADDRESS,
credit_bureau_id
}) => {
options += getSearchItemLayout({
business_name,
registration_number,
address,
credit_bureau_id
});
});
businessesDiv.innerHTML = options;
shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelectorAll('.sprinque-businesses-item').forEach(item => {
item.addEventListener('click', () => {
const name = item.getAttribute('data-name');
const reg = item.getAttribute('data-reg');
const addressStr = item.getAttribute('data-address');
const creditBureauId = item.getAttribute('data-creditBureauId');
onSelectBusiness(shadowRoot, name, addressStr, reg, creditBureauId);
});
});
}
};
const debouncedOnInput = debounce(function (value) {
onInputCompanyName(value);
});
companyNameInput.addEventListener('input', function (e) {
var _a;
companyNameInput.dataset.creditBureauId = '';
// @ts-ignore
if (((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.value) && e.target.value.length > 2) {
// @ts-ignore
debouncedOnInput(e.target.value);
}
});
// on reg number change
regNumberInput.addEventListener('input', function (e) {
var _a;
companyNameInput.dataset.creditBureauId = '';
// @ts-ignore
if (((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.value) && e.target.value.length > 2) {
// @ts-ignore
const {
isValid,
message
} = checkRegNumber(e.target.value, countrySelect.value, lang);
const divWithWarning = shadowRoot.querySelector(REG_NUMBER_WARNING);
divWithWarning.innerHTML = message;
divWithWarning.style.display = isValid ? 'none' : 'block';
}
});
// fetch seller info and set logo
const {
logo
} = await request('seller', shadowRoot, undefined, 'GET');
const logoElem = shadowRoot.querySelector('.sprinque-logo');
if (logoElem) logoElem.src = logo || FALLBACK_LOGO_URL;
};
const CURRENCY_SYMBOL = {
EUR: '€',
USD: '$',
GBP: '£'
};
const handlePasteOtpCode = (elem, allDigitsElems) => {
elem.addEventListener('paste', event => {
var _a;
event.preventDefault();
let code = (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.getData('text');
// insert code and focus to confirm button
if (code && code.length === 5) {
allDigitsElems.forEach((elem, index) => elem.value = code[index]);
}
});
};
const getAddressFromInputs = shadowRoot => ({
address_line1: shadowRoot.querySelector(ADDRESS_LINE_1).value,
address_line2: shadowRoot.querySelector(ADDRESS_LINE_2).value,
city: shadowRoot.querySelector(ADDRESS_CITY).value,
zip_code: shadowRoot.querySelector(ADDRESS_ZIP).value,
country_code: shadowRoot.querySelector(COUNTRY_SELECT).value
});
const showNetTermsWithPrices = (eligibleNetTerms, prices, shadowRoot) => {
eligibleNetTerms.forEach((termUpperCase, index) => {
// show item
const termLowerCase = termUpperCase.toLowerCase(); // net15
const termItemInput = shadowRoot.querySelector(`#${termLowerCase}`);
const termItemLabel = shadowRoot.querySelector(`[for=${termLowerCase}]`);
termItemLabel.style.display = 'flex';
// set price
const termPrice = shadowRoot.querySelector(`.payment-term-price.${termLowerCase}`);
const {
order_amount,
order_currency
} = SprinqueModal.order;
const priceInPercent = prices ? +prices[termLowerCase] : 0;
const cost = priceInPercent * order_amount / 100;
const currencySymbol = CURRENCY_SYMBOL[order_currency];
const formattedCost = currencySymbol + cost.toFixed(2);
termPrice.innerHTML = cost === 0 ? i18next.t(`order.free`) : formattedCost;
termItemInput.dataset.priceAbsolut = String(cost.toFixed(2));
// select first item as default
if (index === 0) {
termItemInput.checked = true;
// set total amount
shadowRoot.querySelector(ORDER_TOTAL_CURRENCY).innerHTML = currencySymbol;
shadowRoot.querySelector(ORDER_TOTAL_AMOUNT).innerHTML = (order_amount + cost).toFixed(2);
}
});
};
const collectBuyerPayload = shadowRoot => {
var _a, _b;
const {
creditBureauId = '',
ipv4 = '',
continentCode = '',
continentName = '',
countryCode = '',
countryName = '',
city = ''
} = shadowRoot.getElementById(COMPANY_NAME.replace('#', '')).dataset;
const buyer = {
business_name: getElemValueBySelector(COMPANY_NAME, shadowRoot),
legal_form: 'Sole Proprietorship',
address: getAddressFromInputs(shadowRoot),
//website: 'http://wisozk-schiller.com',
merchant_buyer_id: String(new Date().getTime()),
//vat_id: '8273JK',
registration_number: getElemValueBySelector('#sp-reg-number', shadowRoot),
buyer_users: [{
first_name: getElemValueBySelector('#sp-user-name', shadowRoot),
last_name: getElemValueBySelector('#sp-user-surname', shadowRoot),
phone: (itiPhoneInput === null || itiPhoneInput === void 0 ? void 0 : itiPhoneInput.getNumber()) || getElemValueBySelector(USER_PHONE, shadowRoot),
email: getElemValueBySelector(USER_EMAIL, shadowRoot)
//language: 'English',
}],
metadata: {}
};
// billing email
const billingEmail = getElemValueBySelector(BILLING_EMAIL, shadowRoot);
if (billingEmail) buyer.email = billingEmail;
// initial_shipping_address
if ((_a = SprinqueModal.order) === null || _a === void 0 ? void 0 : _a.shipping_address) {
buyer['initial_shipping_address'] = (_b = SprinqueModal.order) === null || _b === void 0 ? void 0 : _b.shipping_address;
}
if (creditBureauId) buyer['credit_bureau_id'] = creditBureauId;
if (ipv4) buyer.metadata.IPv4 = ipv4;
if (continentCode) buyer.metadata.continent_code = continentCode;
if (continentName) buyer.metadata.continent_name = continentName;
if (countryCode) buyer.metadata.country_code = countryCode;
if (countryName) buyer.metadata.country_name = countryName;
if (city) buyer.metadata.city = city;
return buyer;
};
const enableOtpButton = shadowRoot => {
const INTERVAL = 30;
const otpRootSpan = shadowRoot.getElementById('resend-code');
const otpSecondsValue = shadowRoot.getElementById('resend-code-sec');
if (!otpRootSpan.classList.contains('disabled')) {
otpRootSpan.classList.add('disabled');
}
let currentSec = 0;
const interval = setInterval(() => {
currentSec += 1;
otpSecondsValue.innerHTML = String(+otpSecondsValue.innerHTML - 1);
// interval is ended
if (currentSec === INTERVAL) {
otpSecondsValue.innerHTML = String(INTERVAL);
clearInterval(interval);
otpRootSpan.classList.remove('disabled');
}
}, 1000);
};
const sendOtpCode = async (email, merchantBuyerId, shadowRoot) => {
await request('business/buyer/email/otp', shadowRoot, {
email: email,
merchant_buyer_id: merchantBuyerId
});
};
const registerStep3Listeners = shadowRoot => {
// on next step
shadowRoot.addEventListener(`${CUSTOM_NAVIGATION_EVENT}4`, async () => {
var _a;
const buyerResponse = await request('buyers/', shadowRoot, collectBuyerPayload(shadowRoot));
if (!buyerResponse.buyer_users) return; // handle failure
const currentEmail = shadowRoot.querySelector(USER_EMAIL).value;
shadowRoot.querySelector(USER_EMAIL_TO).innerHTML = currentEmail;
sessionStorage.setItem(MERCHANT_BUYER_ID, buyerResponse.merchant_buyer_id);
sessionStorage.setItem(BUYER_ID, buyerResponse.buyer_id);
const isEmailOtpValidated = ((_a = buyerResponse.buyer_users.find(user => user.email === currentEmail)) === null || _a === void 0 ? void 0 : _a.email_otp_validated) || false;
// request otp code if needed
if (isEmailOtpValidated) {
// go to next step
const nextStepBtn = shadowRoot.querySelector('[data-validate-step="4"]');
nextStepBtn.click();
} else {
await sendOtpCode(currentEmail, buyerResponse.merchant_buyer_id, shadowRoot);
// focus to the first input
(shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(OTP_DIGIT)).focus();
// start otp timer
enableOtpButton(shadowRoot);
}
});
// on resend code
shadowRoot.querySelector('#resend-code').addEventListener('click', async () => {
const currentEmail = shadowRoot.querySelector(USER_EMAIL).value;
const merchantBuyerId = sessionStorage.getItem(MERCHANT_BUYER_ID);
await sendOtpCode(currentEmail, merchantBuyerId, shadowRoot);
// start otp timer
enableOtpButton(shadowRoot);
});
};
const registerNavBtnListeners = (shadowRoot, onChangeStep) => {
shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelectorAll('.nav').forEach(item => {
item.addEventListener('click', () => {
const step = item.getAttribute('data-to-step');
// validation
const stepToValidate = item.getAttribute('data-validate-step');
if (stepToValidate && !isValidStep(stepToValidate, shadowRoot)) {
return;
}
// handle step change
onChangeStep(step);
// dispatch custom event
const event = new CustomEvent(`${CUSTOM_NAVIGATION_EVENT}${step}`, {
bubbles: true
});
item.dispatchEvent(event);
});
});
};
const automaticallyGoToStep = (step, onChangeStep, shadowRoot) => {
const event = new CustomEvent(`${CUSTOM_NAVIGATION_EVENT}${step}`, {
bubbles: true
});
shadowRoot.dispatchEvent(event);
onChangeStep(`${step}`);
};
const setInitialBuyerInfo = async (shadowRoot, buyerId, onChangeStep) => {
var _a, _b, _c;
// get buyer details
const buyerResponse = await request(`buyers/${buyerId}`, shadowRoot, undefined, 'GET');
const {
address: {
address_line1,
address_line2,
city,
country: {
code
},
zip_code
},
business_name,
registration_number,
buyer_users
} = buyerResponse;
// set values for step 1 (company)
shadowRoot.querySelector(COUNTRY_SELECT).value = code;
shadowRoot.querySelector(COMPANY_NAME).value = business_name;
shadowRoot.querySelector(REG_NUMBER).value = registration_number;
(_a = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(COMPANY_NAME)) === null || _a === void 0 ? void 0 : _a.removeAttribute('disabled');
(_b = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(REG_NUMBER)) === null || _b === void 0 ? void 0 : _b.removeAttribute('disabled');
const nextBtn = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelector(STEP_1_NEXT_BTN);
nextBtn === null || nextBtn === void 0 ? void 0 : nextBtn.removeAttribute('disabled');
// display "search by" label
const {
searchByVat = ''
} = (_c = shadowRoot.getElementById(`country-${code}`)) === null || _c === void 0 ? void 0 : _c.dataset;
displayCorrectLabelForBusinessSearch(searchByVat, shadowRoot);
// set values for step 2 (address)
shadowRoot.querySelector(ADDRESS_LINE_1).value = address_line1;
shadowRoot.querySelector(ADDRESS_LINE_2).value = address_line2;
shadowRoot.querySelector(ADDRESS_CITY).value = city;
shadowRoot.querySelector(ADDRESS_ZIP).value = zip_code;
// set values for step 3 (user)
const user = buyer_users.find(({
email_otp_validated
}) => email_otp_validated) || buyer_users[0];
shadowRoot.querySelector(USER_NAME).value = user.first_name;
shadowRoot.querySelector(USER_SURNAME).value = user.last_name;
shadowRoot.querySelector(USER_EMAIL).value = user.email;
shadowRoot.querySelector(USER_PHONE).value = user.phone;
// move to step 4 automatically
automaticallyGoToStep('4', onChangeStep, shadowRoot);
};
const verifyOtpCode = async (email, merchantBuyerId, code, shadowRoot) => {
return await request('business/buyer/email/otp/verify', shadowRoot, {
email: email,
merchant_buyer_id: merchantBuyerId,
otp: code
});
};
const registerStep4Listeners = (shadowRoot, onChangeStep) => {
// on change otp digit
const allDigits = shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.querySelectorAll(OTP_DIGIT);
const confirmOtpBtn = shadowRoot.querySelector('#confirm-otp-code');
allDigits.forEach((item, index) => {
item.addEventListener('keyup', event => {
// @ts-ignore - only one symbol is allowed
item.value = event.target.value.slice(-1);
const allValuesEntered = [...allDigits].every(digit => digit.value);
if (allValuesEntered) {
confirmOtpBtn.removeAttribute('disabled');
} else {
confirmOtpBtn.setAttribute('disabled', 'true');
}
// focus
if (index !== 4 && item.nextElementSibling) {
item.nextElementSibling.focus();
}
});
// handle paste code
if (index === 0) handlePasteOtpCode(item, allDigits);
});
// on submit otp code
confirmOtpBtn.addEventListener('click', async () => {
const code = [...allDigits].map(digit => digit.value).join('');
const currentEmail = shadowRoot.querySelector(USER_EMAIL).value;
const merchantBuyerId = sessionStorage.getItem(MERCHANT_BUYER_ID);
const response = await verifyOtpCode(currentEmail, merchantBuyerId, code, shadowRoot);
// manage error and next step
const error = shadowRoot.querySelector(`.${VALIDATION_ERROR_CLASS_PREFIX}4`);
if (response.email_otp_validated) {
confirmOtpBtn.style.display = 'none';
const nextBtn = shadowRoot.querySelector("[data-validate-step='4']");
nextBtn.click();
} else {
error.innerHTML = i18next.t('validation.wrongOtp');
}
});
// on next step
shadowRoot.addEventListener(`${CUSTOM_NAVIGATION_EVENT}5`, async () => {
// get single buyer details
const buyerResponse = await request(`buyers/${sessionStorage.getItem(BUYER_ID)}`, shadowRoot, undefined, 'GET');
// execute the callback
if (SprinqueModal.onBuyerResponse) SprinqueModal.onBuyerResponse(buyerResponse);
// show values
if (buyerResponse.credit_qualification) {
const {
credit_decision,
eligible_payment_terms
} = buyerResponse.credit_qualification;
shadowRoot.querySelector('#buyer-credit-decision').innerHTML = credit_decision;
shadowRoot.querySelector('#buyer-net-terms').innerHTML = eligible_payment_terms.join(', ');
const isBuyerApproved = credit_decision === 'APPROVED';
// set price for net terms
if (isBuyerApproved && SprinqueModal.order) {
const {
buyer_pricing_fee_percent
} = await request('seller/pricing', shadowRoot, undefined, 'GET');
showNetTermsWithPrices(eligible_payment_terms, buyer_pricing_fee_percent, shadowRoot);
} else {
automaticallyGoToStep('6', onChangeStep, shadowRoot);
}
}
});
};
const LOADER = `
<style>
.sprinque-ellipsis {
display: none;
position: relative;
margin: 0 auto;
width: 80px;
height: 20px;
}
.sprinque-ellipsis div {
position: absolute;
top: 12px;
width: 13px;
height: 13px;
border-radius: 50%;
background: ${ACTIVE_ITEM_COLOR};
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}
.sprinque-ellipsis div:nth-child(1) {
left: 8px;
animation: sprinque-ellipsis1 0.6s infinite;
}
.sprinque-ellipsis div:nth-child(2) {
left: 8px;
animation: sprinque-ellipsis2 0.6s infinite;
}
.sprinque-ellipsis div:nth-child(3) {
left: 32px;
animation: sprinque-ellipsis2 0.6s infinite;
}
.sprinque-ellipsis div:nth-child(4) {
left: 56px;
animation: sprinque-ellipsis3 0.6s infinite;
}
@keyframes sprinque-ellipsis1 {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
@keyframes sprinque-ellipsis3 {
0% {
transform: scale(1);
}
100% {
transform: scale(0);
}
}
@keyframes sprinque-ellipsis2 {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(24px, 0);
}
}
</style>
<div class="sprinque-ellipsis">
<div></div><div></div><div></div><div></div>
</div>
`;
const STYLE$1 = `
<style>
/* step 1 */
#sprinque-businesses {
overflow-x: scroll;
max-height: 190px;
background: ${LIGHT_COLOR};
border: 1px solid ${BORDER_COLOR};
border-radius: 10px;
margin: 10px 0;
}
#sprinque-businesses:empty {display: none}
.sprinque-businesses-item {
padding: 10px;
margin: 5px;
}
.sprinque-businesses-item:not(:last-child) {
border-bottom: 1px solid ${BORDER_COLOR};
}
/* checkboxes from https://www.w3schools.com/howto/howto_css_custom_checkbox.asp */
/* Customize the label (the container) */
${SEARCH_TYPE} {
margin-bottom: 5px;
}
${SEARCH_TYPE} label {
position: relative;
padding-left: 25px;
margin-right: 20px;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.sdk-lang-de #search-type label {
max-width: 140px;
word-wrap: break-word;
}
/* Hide the browser's default checkbox */
${SEARCH_TYPE} input {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
/* Create a custom checkbox */
.sp-checkmark {
position: absolute;
top: 7px;
left: 0;
height: 16px;
width: 16px;
border: 1px solid ${ACTIVE_ITEM_COLOR};
border-radius: 50%;
}
/* On mouse-over, add a grey background color */
${SEARCH_TYPE}:hover input ~ .sp-checkmark {
background-color: #ccc;
}
/* Create the checkmark/indicator (hidden when not checked) */
.sp-checkmark:after {
content: "";
position: absolute;
display: none;
}
/* Show the checkmark when checked */
${SEARCH_TYPE} input:checked ~ .sp-checkmark:after {
display: block;
}
/* Style the checkmark/indicator */
${SEARCH_TYPE} .sp-checkmark:after {
left: 3px;
top: 3px;
width: 10px;
height: 10px;
background: ${ACTIVE_ITEM_COLOR};
border-radius: 50%;
}
</style>
`;
const getStep1 = () => `
${STYLE$1}
<div class='${SPRINQUE_STEP_CLASS}-1'>
<div class='sprinque-header'>
<h3>${i18next.t('business.title')}</h3>
<span class='sprinque-stepper'>${i18next.t('general.step')} 1/4</span>
</div>
<p>${i18next.t('business.description')}</p>
<div id='sp-form-step-1'>
<!-- country select -->
<label for=${COUNTRY_SELECT.replace('#', '')}>${i18next.t('business.country')}*</label>
<select id=${COUNTRY_SELECT.replace('#', '')} required>
<option value='' selected disabled>${i18next.t('business.loading')}...</option>
</select>
<div style='display: none' id=${SEARCH_TYPE.replace('#', '')} data-search-by='NAME'>
<!-- by name -->
<label for=${SEARCH_BY_NAME.replace('#', '')}>
<input type="radio" id=${SEARCH_BY_NAME.replace('#', '')} name='search-by' checked>
<span class="sp-checkmark"></span>${i18next.t('business.companyName')}
</label>
<!-- by vat id -->
<label for=${SEARCH_BY_VAT.replace('#', '')}>
<input type="radio" id=${SEARCH_BY_VAT.replace('#', '')} name='search-by'>
<span class="sp-checkmark"></span>${i18next.t('business.vatId')}
</label>
</div>
<!-- company name -->
<label for=${COMPANY_NAME.replace('#', '')}>${i18next.t('business.companyName')}*</label>
<input type="text" id=${COMPANY_NAME.replace('#', '')} disabled required placeholder='${i18next.t('business.search')}'>
${LOADER}
<div id='sprinque-businesses'></div>
<!-- reg number -->
<label for=${REG_NUMBER.replace('#', '')}>
${i18next.t('business.registrationNumber')}
<span id=${REG_NUMBER_ASTERISK.replace('#', '')}>*</span>
</label>
<input type="text" id=${REG_NUMBER.replace('#', '')} disabled>
<!-- warning -->
<div style='display: none' class='warning' id=${REG_NUMBER_WARNING.replace('#', '')}></div>
<!-- billing email -->
<label for=${BILLING_EMAIL.replace('#', '')}>${i18next.t('business.billingEmail')}*</label>
<input type="text" id=${BILLING_EMAIL.replace('#', '')}>
<br>
<div class='${VALIDATION_ERROR_CLASS_PREFIX}1'></div>
<div class='sprinque-text-right'>
<button class='nav' data-validate-step='1' data-to-step='2' disabled>${i18next.t('general.next')}<i class="sp-arrow sp-right"></i></button>
</div>
</div>
</div>
`;
const getStep2 = () => `
<div class='${SPRINQUE_STEP_CLASS}-2' style='display: none'>
<div class='sprinque-header'>
<h3>${i18next.t('address.title')}</h3>
<span class='sprinque-stepper'>${i18next.t('general.step')} 2/4</span>
</div>
<p>${i18next.t('address.description')}</p>
<div id='sp-form-step-2'>
<!-- address line 1 -->
<label for="sp-address-line1">${i18next.t('address.line1')}*</label>
<input type="text" id=${ADDRESS_LINE_1.replace('#', '')} required name="sp-address-line1">
<!-- address line 2 -->
<label for="sp-address-line2">${i18next.t('address.line2')}</label>
<input type="text" id=${ADDRESS_LINE_2.replace('#', '')} required name="sp-address-line2">
<!-- city -->
<label for="sp-address-city">${i18next.t('address.city')}*</label>
<input type="text" id=${ADDRESS_CITY.replace('#', '')} required name="sp-address-city">
<!-- zip -->
<label for="sp-address-zip">${i18next.t('address.zip')}*</label>
<input type="text" id=${ADDRESS_ZIP.replace('#', '')} required name="sp-address-zip">
<br>
<br>
<div class='${VALIDATION_ERROR_CLASS_PREFIX}2'></div>
<div class='justify-between'>
<button class='nav secondary' data-to-step='1'><i class="sp-arrow sp-left"></i>
${i18next.t('general.back')}
</button>
<button class='nav' data-validate-step='2' data-to-step='3'>
${i18next.t('general.next')}
<i class="sp-arrow sp-right"></i>
</button>
</div>
</div>
</div>
`;
const STYLE_STEP_3 = `
<style>
/* step 3 */
.iti__flag {background-image: url("https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.21/img/flags.png");}
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
.iti__flag {background-image: url("https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.21/img/flags@2x.png");}
}
.iti--allow-dropdown {width: 100%}
#sp-user-phone {width: 100%}
</style>
`;
const getStep3 = () => `
<div class='${SPRINQUE_STEP_CLASS}-3' style='display: none'>
<!-- styles for intl-tel-input -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.21/css/intlTelInput.css" integrity="sha512-gxWow8Mo6q6pLa1XH/CcH8JyiSDEtiwJV78E+D+QP0EVasFs8wKXq16G8CLD4CJ2SnonHr4Lm/yY2fSI2+cbmw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
${STYLE_STEP_3}
<!-- #styles for intl-tel-input -->
<div class='sprinque-header'>
<h3>${i18next.t('contact.title')}</h3>
<span class='sprinque-stepper'>${i18next.t('general.step')} 3/4</span>
</div>
<p>${i18next.t('contact.description')}</p>
<div id='sp-form-step-3'>
<!-- First name -->
<label for="sp-user-name">${i18next.t('contact.name')}*</label>
<input type="text" id=${USER_NAME.replace('#', '')} required>
<!-- Last name -->
<label for="sp-user-surname">${i18next.t('contact.surname')}*</label>
<input type="text" id=${USER_SURNAME.replace('#', '')} required>
<!-- Email -->
<label for="sp-user-email">${i18next.t('contact.email')}*</label>
<input type="text" id=${USER_EMAIL.replace('#', '')} required>
<!-- Phone -->
<label for="sp-user-phone">${i18next.t('contact.phone')}*</label>
<input type="text" id=${USER_PHONE.replace('#', '')} required>
<br>
<br>
<div class='${VALIDATION_ERROR_CLASS_PREFIX}3'></div>
<div class='justify-between'>
<button class='nav secondary' data-to-step='2'><i class="sp-arrow sp-left"></i>${i18next.t('general.back')}</button>
<button class='nav' data-validate-step='3' data-to-step='4'>${i18next.t('general.next')}<i class="sp-arrow sp-right"></i></button>
</div>
</div>
</div>
`;
const STYLE = `
<style>
/* step 4 */
#sp-otp-digits {
display: flex;
}
.sp-otp-digit {
width: 20%;
border: none;
background: none;
outline: none;
border-bottom: 2px solid #333232;
font-size: 30px;
margin: 20px 5px;
border-radius: 0;
color: ${ACTIVE_ITEM_COLOR};
text-align: center;
}
#resend-code {
color: ${FORM_ELEM_COLOR};
cursor: pointer;
}
#resend-code:not(.disabled) #resend-code-desc {
display: none;
}
#resend-code.disabled {
pointer-events: none;
opacity: 0.5;
}
/* hide arrows */
.sp-otp-digit::-webkit-outer-spin-button,
.sp-otp-digit::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
.sp-otp-digit[type=number] {
-moz-appearance: textfield;
}
</style>
`;
const getStep4 = () => `
${STYLE}
<div class='${SPRINQUE_STEP_CLASS}-4' style='display: none'>
<div class='sprinque-header'>
<h3>${i18next.t('otp.title')}</h3>
<span class='sprinque-stepper'>${i18next.t('general.step')} 4/4</span>
</div>
<p>
${i18next.t('otp.description')} <strong id=${USER_EMAIL_TO.replace('#', '')}></strong>
</p>
<div id='sp-form-step-4'>
${LOADER}
<!-- digits -->
<div id='sp-otp-digits'>
<input class='sp-otp-digit sp-otp-1' type='number' maxlength='1' min="0" max='9'>
<input class='sp-otp-digit sp-otp-2' type='number' maxlength='1' min="0" max='9'>
<input class='sp-otp-digit sp-otp-3' type='number' maxlength='1' min="0" max='9'>
<input class='sp-otp-digit sp-otp-4' type='number' maxlength='1' min="0" max='9'>
<input class='sp-otp-digit sp-otp-5' type='number' maxlength='1' min="0" max='9'>
</div>
<div class='${VALIDATION_ERROR_CLASS_PREFIX}4'></div>
<div class='justify-between'>
<button class='nav secondary' data-to-step='3'><i class="sp-arrow sp-left"></i>
${i18next.t('general.back')}
</button>
<button style='display:none' class='nav' data-validate-step='4' data-to-step='5'>
${i18next.t('general.next')}
<i class="sp-arrow sp-right"></i>
</button>
<button disabled id='confirm-otp-code'>${i18next.t('general.confirm')}</button>
</div>
<p style='margin: 10px 0'>
${i18next.t('otp.notReceivedText')}
<span id='resend-code' class='disabled'>
${i18next.t('otp.resendCode')}
<span id='resend-code-desc'> (${i18next.t('otp.timerBeforeText')}
<span id='resend-code-sec'>30</span> ${i18next.t('otp.timerAfterText')})</span>
</span>
</p>
</div>
</div>
`;
const STYLE_STEP_5 = `
<style>
.payment-term-item label {
}
/*From https://www.w3schools.com/howto/howto_css_custom_checkbox.asp*/
/* Customize the label (the payment-term-item) */
.payment-term-item {
position: relative;
padding: 10px 10px 10px 40px;
margin: 10px 0;
font-weight: normal;
color: ${ACTIVE_ITEM_COLOR};
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
border: 1px solid ${BORDER_COLOR};
}
.payment-term-item:has(input:checked) {
border: 1px solid ${ACTIVE_ITEM_COLOR};
}
/* Hide the browser's default radio button */
.payment-term-item input {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
/* Create a custom radio button */
.checkmark {
position: absolute;
top: 12px;
left: 11px;
height: 20px;
width: 20px;
background-color: ${BORDER_COLOR};
border-radius: 50%;
transition: background-color 0.2s;
}
/* On mouse-over, add a grey background color */
.payment-term-item:hover input ~ .checkmark {
background-color: #ccc;
}
/* When the radio button is checked, add a blue background */
.payment-term-item input:checked ~ .checkmark {
background-color: ${ACTIVE_ITEM_COLOR};
}
/* Create the indicator (the dot/circle - hidden when not checked) */
.checkmark:after {
content: "";
position: absolute;
display: none;
}
/* Show the indicator (dot/circle) when checked */
.payment-term-item input:checked ~ .checkmark:after {
display: block;
}
/* Style the indicator (dot/circle) */
.payment-term-item .checkmark:after {
top: 6px;
left: 5px;
width: 8px;
height: 4px;
border-left: 2px solid ${LIGHT_COLOR};
border-bottom: 2px solid ${LIGHT_COLOR};
rotate: -47deg;
}
</style>
`;
const getStep5 = () => `
${STYLE_STEP_5}
<div class='${SPRINQUE_STEP_CLASS}-5' style='display: none'>
<div class='sprinque-header'>
<h3>${i18next.t('order.title')}</h3>
</div>
<p>${i18next.t('order.description')}</p>
<div id='sp-form-step-5'>
${LOADER}
<div class='justify-between' style='margin-top: 20px'>
<span><strong>${i18next.t('order.totalAmount')}</strong></span>
<strong>
<span id='order-total-currency'>-</span>
<span id='order-total-amount'>-</span>
</strong>
</div>
<!-- select payment terms -->
${SUPPORTED_NET_TERMS.map(term => `<label style='display: none' for="${term}" class='payment-term-item justify-between'>
<div>
<input type="radio" id="${term}" name="net-terms" value="${term}">
<span>${i18next.t(`order.${term}`)}</span>
<span class="checkmark"></span>
</div>
<div class="payment-term-price ${term}">-</div>
</label>`).join('')} <!-- join will hide comma -->
<div class='${VALIDATION_ERROR_CLASS_PREFIX}5'></div>
<div class='justify-between'>
<button style='width: 100%' id='place-order' class='nav' data-validate-step='5' data-to-step='6'>
${i18next.t('order.confirmOrder')}
</button>
</div>
</div>
</div>
`;
const getStep6 = () => `
<div class='${SPRINQUE_STEP_CLASS}-6' style='display: none'>
<div class='sprinque-header'>
<h3>${i18next.t('success.title')}</h3>
</div>
<div id='sp-form-step-6'>
${LOADER}
<div class='justify-between'>${i18next.t('success.creditDecision')}: <strong><span id='buyer-credit-decision'>-</span></strong>
</div>
<div class='justify-between'>${i18next.t('success.paymentTerms')}: <strong><span id='buyer-net-terms'>-</span></strong>
</div>
<div style='padding: 10px 0; margin: 10px 0;border-top: 1px solid ${BORDER_COLOR}; border-bottom: 1px solid ${BORDER_COLOR};'>
${i18next.t('success.description')}
</div>
<!-- Order info -->
<div id='order-info' style='display: none'>
<h3>${i18next.t('success.orderPlaced')}</h3>
<div class='justify-between'>${i18next.t('success.transactionId')}: <strong id='order-id'></strong></div>
</div>
<br>
<br>
<div class='${VALIDATION_ERROR_CLASS_PREFIX}6'></div>
</div>
</div>
`;
const pj = require(process.env.NODE_ENV === 'development' ? '../../package.json' : '../package.json');
const getTemplate = lang => {
const template = document.createElement('template');
template.innerHTML = `
${MAIN_STYLES}
<div class="sprinque-modal-wrapper sdk-lang-${lang}">
<div class="sprinque-modal">
<!-- logo -->
<div class='sprinque-logo-wrapper'>
<img class='sprinque-logo' src='${FALLBACK_LOGO_URL}' alt='b2b logo'/>
</div>
<span class="close-btn">×</span>
${getStep1()}
${getStep2()}
${getStep3()}
${getStep4()}
${getStep5()}
${getStep6()}
<!-- api error -->
<p class=${API_ERROR_ELEM.replace('.', '')} style='display: none'>Something went wrong.</p>
<!-- powered by -->
<div class='powered-by'>
<div>Powered by <img class='sprinque-powered-img' src=${FALLBACK_LOGO_URL} alt='sprinque'></div>
<div>v.${pj.version}</div>
</div>
</div>
</div>`;
return template;
};
const registerStep5Listeners = shadowRoot => {
var _a;
// on net terms change
const netTermInputs = shadowRoot.querySelectorAll('[name="net-terms"]');
const orderAmount = Number((_a = SprinqueModal.order) === null || _a === void 0 ? void 0 : _a.order_amount) || 0;
if (orderAmount) {
netTermInputs.forEach(input => {
input.addEventListener('change', event => {
const {
priceAbsolut
} = event.target.dataset;
shadowRoot.querySelector(ORDER_TOTAL_AMOUNT).innerHTML = (orderAmount + Number(priceAbsolut)).toFixed(2);
});
});
}
// on next step
shadowRoot.addEventListener(`${CUSTOM_NAVIGATION_EVENT}6`, async () => {
var _a;
// place order if buyer approved
if (SprinqueModal.order) {
const currentEmail = shadowRoot.querySelector(USER_EMAIL).value;
const payment_terms = (_a = shadowRoot.querySelector('[name="net-terms"]:checked').value) === null || _a === void 0 ? void 0 : _a.toUpperCase();
const authPayload = Object.assign(Object.assign({}, SprinqueModal.order), {
issued_by: currentEmail,
payment_terms
});
// add ip address
const {
ipv4 = '',
continentCode = '',
continentName = '',
countryCode = '',
countryName = '',
city = ''
} = shadowRoot.querySelector(COMPANY_NAME).dataset;
// @ts-ignore
if (ipv4) authPayload.metadata.IPv4 = ipv4;
// @ts-ignore
if (continentCode) authPayload.metadata.continent_code = continentCode;
// @ts-ignore
if (continentName) authPayload.metadata.continent_name = continentName;
// @ts-ignore
if (countryCode) authPayload.metadata.country_code = countryCode;
// @ts-ignore
if (countryName) authPayload.metadata.country_name = countryName;
// @ts-ignore
if (city) authPayload.metadata.city = city;
const authTransactionResponse = await request(`transactions/authorize/${sessionStorage.getItem(BUYER_ID)}`, shadowRoot, authPayload);
const {
errors
} = authTransactionResponse;
if (!errors) {
shadowRoot.getElementById('order-info').style.display = 'block';
shadowRoot.getElementById('order-id').innerHTML = authTransactionResponse.transaction_id;
// callback
if (SprinqueModal.onOrderCreated) SprinqueModal.onOrderCreated(authTransactionResponse);
}
}
});
};
class SprinqueModal extends HTMLElement {
constructor() {
super();
this.changeStep = (value = '1') => {
showNextStep(this.shadowRoot, this.step, value);
this.step = value;
};
this.step = '1';
}
async connectedCallback() {
this.attachShadow({
mode: 'open'
});
const lang = this.getAttribute('lang') || 'en';
if (this.shadowRoot) {
this.shadowRoot.appendChild(getTemplate(lang).content.cloneNode(true));
}
const buyerId = this.getAttribute('buyer-id');
if (this.shadowRoot) {
// close on the wrapper click
registerModalBgListener(this.shadowRoot);
// STEP 1
await registerStep1Listeners(this.shadowRoot, lang, buyerId);
// STEP 2
registerStep2Listeners(this.shadowRoot);
// STEP 3
registerStep3Listeners(this.shadowRoot);
// STEP 4
registerStep4Listeners(this.shadowRoot, this.changeStep);
// STEP 5
registerStep5Listeners(this.shadowRoot);
// navigation buttons
registerNavBtnListeners(this.shadowRoot, this.changeStep);
if (buyerId) {
await setInitialBuyerInfo(this.shadowRoot, buyerId, this.changeStep);
}
}
}
}
var business = {
title: "Select your business",
description: "To approve a payment term for your order we need your company information to run a soft and quick credit check.",
country: "Country",
selectCountry: "Select country",
loading: "Loading",
companyName: "Company name",
vatId: "VAT ID",
search: "Search",
registrationNumber: "Registration number",
billingEmail: "Billing or Accounts Payable email",
cantFind: "Can’t find your business?",
cantFindInstruction: "You can continue by manually filling the details below."
};
var address = {
title: "Company address",
description: "Please add your company registration address",
line1: "Address",
line2: "Apartment, suite, etc",
city: "City",
zip: "Postal code"
};
var contact = {
title: "User details",
description: "Please provide your details for this purchase.",
name: "Name",
surname: "Last name",
email: "Business email address",
phone: "Phone number"
};
var otp = {
title: "Verify your email",
description: "We sent a verification code to",
notReceivedText: "Did’t receive the code?",
resendCode: "Click to resend",
timerBeforeText: "in",
timerAfterText: "seconds"
};
var order = {
title: "Congratulations!",
description: "You’ve been approved to pay with net terms. Select the payment term that best suits your company",
totalAmount: "Total amount",
confirmOrder: "Confirm order",
free: "Free",
net7: "Net 7 days",
net15: "Net 15 days",
net30: "Net 30 days",
net45: "Net 45 days",
net60: "Net 60 days",
net90: "Net 90 days"
};
var success = {
title: "Buyer registered",
description: "You can execute callback instead of this screen. Check console to see example...",
creditDecision: "Credit decision",
paymentTerms: "Payment terms",
orderPlaced: "You've placed order",
transactionId: "Transaction id"
};
var general = {
step: "Step",
next: "Next",
back: "Prev",
confirm: "Confirm"
};
var validation = {
invalidCountryCode: "Invalid country code",
phoneIsShort: "Phone number is too short",
phoneIsLong: "Phone number is too long",
invalidPhone: "Please input a valid phone number",
fillAllFields: "Please fill all required fields",
invalidEmail: "Please input a valid email",
wrongOtp: "The code you entered is incorrect. Please try again"
};
var en = {
business: business,
address: address,
contact: contact,
otp: otp,
order: order,
success: success,
general: general,
validation: validation
};
var nl = {
"address.city": "Stad",
"address.cityExample": "Amsterdam",
"address.description": "Controleer of dit het juiste adres is door de volgende stap te volgen. Als dit niet het juiste adres is, werk het dan handmatig bij.",
"address.line1": "Adres",
"address.line1Example": "Prinsengracht",
"address.line2": "Appartement, suite, enz.",
"address.line2Example": "526 H",
"address.title": "Adres van het bedrijf",
"address.zip": "Postcode",
"address.zipExample": "1017 KJ",
"business.billingEmail": "Facturering of crediteuren e-mail",
"business.cantFind": "Kan je jouw bedrijf niet vinden?",
"business.cantFindInstruction": "Je kunt doorgaan door onderstaande gegevens handmatig in te vullen.",
"business.companyName": "Bedrijfsnaam",
"business.country": "Land",
"business.description": "Voer eerst je bedrijfsgegevens in om jouw aankoop goed te keuren.",
"business.loading": "Laden",
"business.registrationNumber": "Registratienummer",
"business.registrationNumberExample": "819770500000",
"business.search": "Zoeken",
"business.selectCountry": "Selecteer land",
"business.startTyping": "Begin met typen",
"business.title": "Selecteer jouw bedrijf",
"business.vatId": "BTW-NUMMER",
"contact.description": "Maak een contactprofiel aan naar wie facturen en betalingsherinneringen zullen worden gestuurd.",
"contact.email": "E-mail gebruiker",
"contact.emailExample": "john@company.io",
"contact.name": "Voornaam",
"contact.nameExample": "John",
"contact.phone": "Telefoonnummer",
"contact.phoneExample": "+3168798526",
"contact.surname": "Achternaam",
"contact.surnameExample": "Doe",
"contact.title": "Contact aanmaken",
"general.back": "Terug",
"general.confirm": "Bevestig",
"general.next": "Volgende",
"general.step": "Stap",
"order.confirmOrder": "Bevestig bestelling",
"order.description": "je bent goedgekeurd om met netto termijnen te betalen. Selecteer de betalingstermijn die het beste bij jouw bedrijf past",
"order.free": "Gratis",
"order.net15": "Netto 15 dagen",
"order.net30": "Netto 30 dagen",
"order.net45": "Netto 45 dagen",
"order.net60": "Netto 60 dagen",
"order.net7": "Netto 7 dagen",
"order.net90": "Netto 90 dagen",
"order.title": "Gefeliciteerd!",
"order.totalAmount": "Totaal bedrag",
"otp.description": "Om er zeker van te zijn dat je het echt bent, hebben we een code gestuurd naar",
"otp.notReceivedText": "Als je de code niet hebt ontvangen, controleer dan je spamfolder of",
"otp.resendCode": "code opnieuw verzenden",
"otp.timerAfterText": "seconden",
"otp.timerBeforeText": "over",
"otp.title": "Controleer je e-mail",
"regNumber.errors.deleteFourLastDigits": "Verwijder de laatste 4 cijfers",
"regNumber.errors.formatIs": "Het formaat van het registratienummer moet zijn",
"regNumber.errors.itIsVat": "De waarde lijkt een btw-nummer te zijn. Volg het formaat zoals",
"regNumber.errors.required": "Registratienummer en landcode zijn vereist",
"success.creditDecision": "Kredietbeslissing",
"success.description": "Je kunt callback uitvoeren in plaats van dit scherm. Controleer de console om een voorbeeld te zien...",
"success.orderPlaced": "Je hebt een bestelling geplaatst",
"success.paymentTerms": "Betalingsvoorwaarden",
"success.title": "Koper geregistreerd",
"success.transactionId": "Transactie-id",
"validation.fillAllFields": "Gelieve alle verplichte velden in te vullen",
"validation.invalidCountryCode": "Ongeldige landcode",
"validation.invalidEmail": "Voer een geldig e-mailadres in",
"validation.invalidPhone": "Voer een geldig telefoonnummer in",
"validation.phoneIsLong": "Het telefoonnummer is te lang",
"validation.phoneIsShort": "Het telefoonnummer is te kort",
"validation.wrongOtp": "De ingevoerde code is onjuist. Probeer het opnieuw"
};
var de = {
"address.city": "Stadt",
"address.cityExample": "Amsterdam",
"address.description": "Vergewissere Dich, dass dies die richtige Adresse ist, bevor Du auf Weiter klickst. Wenn dies nicht die richtige Adresse ist, aktualisiere sie bitte manuell.",
"address.line1": "Adresse",
"address.line1Example": "Prinsengracht",
"address.line2": "Wohnung, Appartement, etc.",
"address.line2Example": "526 H",
"address.title": "Adresse des Unternehmens",
"address.zip": "Postleitzahl",
"address.zipExample": "1017 KJ",
"business.billingEmail": "Geschäftliche E-Mail-Adresse",
"business.cantFind": "Du kannst Dein Unternehmen nicht finden?",
"business.cantFindInstruction": "Du kannst fortfahren, indem Du die folgenden Angaben manuell ausfüllst.",
"business.companyName": "Name des Unternehmens",
"business.country": "Land",
"business.description": "Gebe zunächst Deine Unternehmensdaten ein, um Deinen Kauf zu genehmigen.",
"business.loading": "Laden",
"business.registrationNumber": "Handelsregisternummer",
"business.registrationNumberExample": "819770500000",
"business.search": "Suche",
"business.selectCountry": "Land",
"business.startTyping": "Beginne mit dem Tippen",
"business.title": "Bitte wähle Dein Unternehmen",
"business.vatId": "USt-IdNr",
"contact.description": "Bitte lege ein Kontaktprofil an, an das Rechnungen und Zahlungserinnerungen gesendet werden sollen.",
"contact.email": "Benutzer-E-Mail",
"contact.emailExample": "john@company.io",
"contact.name": "Vorname",
"contact.nameExample": "John",
"contact.phone": "Telefonnummer",
"contact.phoneExample": "+3168798526",
"contact.surname": "Nachname",
"contact.surnameExample": "Doe",
"contact.title": "Kontakt erstellen",
"general.back": "Zurück",
"general.confirm": "Bestätigen",
"general.next": "Weiter",
"general.step": "Schritt",
"order.confirmOrder": "Bestellung bestätigen",
"order.description": "Du wurdest für den Kauf auf Rechnung zugelassen. Wähle das Zahlungsziel, das am besten zu Deinem Unternehmen passt",
"order.free": "Kostenlos",
"order.net15": "15 Tage",
"order.net30": "30 Tage",
"order.net45": "45 Tage",
"order.net60": "60 Tage",
"order.net7": "7 Tage",
"order.net90": "90 Tage",
"order.title": "Herzlichen Glückwunsch!",
"order.totalAmount": "Gesamtbetrag",
"otp.description": "Um sicherzugehen, dass Du es wirklich bist, haben wir einen Code an diese E-Mail geschickt: ",
"otp.notReceivedText": "Wenn Sie den Code nicht erhalten haben, überprüfen Sie bitte Ihren Spam-Ordner oder",
"otp.resendCode": "Code erneut senden",
"otp.timerAfterText": "Sekunden",
"otp.timerBeforeText": "in",
"otp.title": "Überprüfen Deine E-Mail",
"regNumber.errors.deleteFourLastDigits": "Bitte entfernen Sie die letzten 4 Ziffern",
"regNumber.errors.formatIs": "Das Format der Handelsregisternummer sollte wie folgt aussehen",
"regNumber.errors.itIsVat": "Der Wert scheint eine USt-IdNr. zu sein. Bitte folgen Sie dem Format wie",
"regNumber.errors.required": "Handelsregisternummer und Ländercode sind erforderlich",
"success.creditDecision": "Kreditentscheidung",
"success.description": "Du kannst anstelle dieses Bildschirms einen Rückruf (Callback) ausführen. Prüfe die Konsole, um ein Beispiel zu sehen...",
"success.orderPlaced": "Du hast eine Bestellung aufgegeben",
"success.paymentTerms": "Zahlungsbedingungen",
"success.title": "Käufer registriert",
"success.transactionId": "Transaktions-ID",
"validation.fillAllFields": "Bitte fülle alle erforderlichen Felder aus",
"validation.invalidCountryCode": "Ungültiger Ländercode",
"validation.invalidEmail": "Bitte gebe eine gültige E-Mail ein",
"validation.invalidPhone": "Bitte gebe eine gültige Telefonnummer ein",
"validation.phoneIsLong": "Die Telefonnummer ist zu lang",
"validation.phoneIsShort": "Die Telefonnummer ist zu kurz",
"validation.wrongOtp": "Der von Dir eingegebene Code ist falsch. Bitte versuche es erneut"
};
var es = {
"address.city": "Ciudad",
"address.cityExample": "Amsterdam",
"address.description": "Confirma que es la dirección correcta siguiendo el siguiente paso. Si esta no es la dirección de tu empresa, actualízala manualmente.",
"address.line1": "Dirección",
"address.line1Example": "Prinsengracht",
"address.line2": "Apartamento, suite, etc.",
"address.line2Example": "526 H",
"address.title": "Dirección de la empresa",
"address.zip": "Código postal",
"address.zipExample": "1017 KJ",
"business.billingEmail": "Email de facturación o cuentas a pagar",
"business.cantFind": "¿No encuentras tu empresa?",
"business.cantFindInstruction": "Puedes continuar rellenando manualmente los datos de tu empresa.",
"business.companyName": "Nombre de la empresa",
"business.country": "País",
"business.description": "Primero ingresa la información de tu empresa para aprobar tu compra.",
"business.loading": "Cargando",
"business.registrationNumber": "Número de registro",
"business.registrationNumberExample": "819770500000",
"business.search": "Buscar",
"business.selectCountry": "Selecciona el país",
"business.startTyping": "Empieza a escribir",
"business.title": "Selecciona tu empresa",
"business.vatId": "VAT ID",
"contact.description": "Crea un contacto al que se enviarán las facturas y los recordatorios de pago.",
"contact.email": "Email ",
"contact.emailExample": "john@company.io",
"contact.name": "Nombre",
"contact.nameExample": "Juan",
"contact.phone": "Número de teléfono",
"contact.phoneExample": "+3168798526",
"contact.surname": "Apellido",
"contact.surnameExample": "Doe",
"contact.title": "Crear contacto",
"general.back": "Atrás",
"general.confirm": "Confirmar",
"general.next": "Siguiente",
"general.step": "Paso",
"order.confirmOrder": "Confirmar pedido",
"order.description": "Tu empresa ha sido aprobada para pagar con factura. Selecciona el plazo de pago que mejor se adapte a tu empresa",
"order.free": "Libre",
"order.net15": "Neto 15 días",
"order.net30": "Neto 30 días",
"order.net45": "Neto 45 días",
"order.net60": "Neto 60 días",
"order.net7": "Neto 7 días",
"order.net90": "Neto 90 días",
"order.title": "¡Felicidades!",
"order.totalAmount": "La cantidad total",
"otp.description": "Para asegurarnos de que realmente eres tú, hemos enviado un código a",
"otp.notReceivedText": "Si no has recibido el código, comprueba tu carpeta de spam o",
"otp.resendCode": "reenviar código",
"otp.timerAfterText": "segundos",
"otp.timerBeforeText": "en",
"otp.title": "Verifica tu correo electrónico",
"regNumber.errors.deleteFourLastDigits": "Por favor, elimina los 4 últimos dígitos",
"regNumber.errors.formatIs": "El formato del número de registro debe ser el siguiente",
"regNumber.errors.itIsVat": "El valor parece ser un VAT ID. El formato es el siguiente",
"regNumber.errors.required": "Se requiere el número de registro y el código de país",
"success.creditDecision": "Decisión de crédito",
"success.description": "Puede ejecutar callback en lugar de esta pantalla. Compruebe la consola para ver un ejemplo...",
"success.orderPlaced": "Has realizado el pedido con éxito",
"success.paymentTerms": "Plazos de pago",
"success.title": "Comprador registrado",
"success.transactionId": "Id de transacción",
"validation.fillAllFields": "Rellena todos los campos obligatorios",
"validation.invalidCountryCode": "Código de país no válido",
"validation.invalidEmail": "Por favor, introduce un email válido",
"validation.invalidPhone": "Ingresa un número de teléfono válido",
"validation.phoneIsLong": "El número es demasiado largo",
"validation.phoneIsShort": "El número es demasiado corto",
"validation.wrongOtp": "El código introducido es incorrecto. Por favor, inténtalo de nuevo."
};
var fr = {
"address.city": "Ville",
"address.cityExample": "Amsterdam",
"address.description": "Confirmez qu'il s'agit de la bonne adresse en passant à l'étape suivante. S'il ne s'agit pas de la bonne adresse, veuillez la mettre à jour manuellement.",
"address.line1": "Adresse",
"address.line1Example": "Prinsengracht",
"address.line2": "Appartement, suite, etc.",
"address.line2Example": "526 H",
"address.title": "Adresse de l'entreprise",
"address.zip": "Code postal",
"address.zipExample": "1017 KJ",
"business.billingEmail": "Courriel de la facturation ou des comptes à payer",
"business.cantFind": "Vous ne trouvez pas votre entreprise ?",
"business.cantFindInstruction": "Vous pouvez continuer en remplissant manuellement les détails ci-dessous.",
"business.companyName": "Nom de l'entreprise",
"business.country": "Pays",
"business.description": "Saisissez d'abord les informations relatives à votre entreprise pour approuver votre achat.",
"business.loading": "Chargement",
"business.registrationNumber": "Numéro d'enregistrement",
"business.registrationNumberExample": "819770500000",
"business.search": "Rechercher",
"business.selectCountry": "Sélectionnez un pays",
"business.startTyping": "Commencez à taper",
"business.title": "Veuillez sélectionner votre entreprise",
"business.vatId": "NUMÉRO DE TVA",
"contact.description": "Veuillez créer un profil de contact auquel les factures et les rappels de paiement seront envoyés.",
"contact.email": "Courriel de l'utilisateur",
"contact.emailExample": "john@company.io",
"contact.name": "Prénom",
"contact.nameExample": "Jean",
"contact.phone": "Numéro de téléphone",
"contact.phoneExample": "+3168798526",
"contact.surname": "Nom de famille",
"contact.surnameExample": "Une biche",
"contact.title": "Créer un contact",
"general.back": "Retour",
"general.confirm": "Confirmer",
"general.next": "Suivant",
"general.step": "Étape",
"order.confirmOrder": "Confirmer la commande",
"order.description": "Vous avez été autorisé à payer avec des conditions nettes. Sélectionnez le délai de paiement qui convient le mieux à votre entreprise",
"order.free": "Gratuit",
"order.net15": "Net 15 jours",
"order.net30": "Net 30 jours",
"order.net45": "Net 45 jours",
"order.net60": "Net 60 jours",
"order.net7": "Net 7 jours",
"order.net90": "Net 90 jours",
"order.title": "Félicitations !",
"order.totalAmount": "Montant total",
"otp.description": "Pour s'assurer qu'il s'agit bien de vous, nous avons envoyé un code à",
"otp.notReceivedText": "Si vous n'avez pas reçu le code, veuillez vérifier votre dossier spam ou",
"otp.resendCode": "Renvoyer le code",
"otp.timerAfterText": "secondes",
"otp.timerBeforeText": "en",
"otp.title": "Vérifiez votre adresse électronique",
"regNumber.errors.deleteFourLastDigits": "Veuillez enlever les 4 derniers chiffres",
"regNumber.errors.formatIs": "Le format du numéro d'enregistrement doit être le suivant",
"regNumber.errors.itIsVat": "La valeur semble être un numéro de TVA. Veuillez suivre le format suivant",
"regNumber.errors.required": "Le numéro d'enregistrement et le code pays sont requis",
"success.creditDecision": "Décision de crédit",
"success.description": "Vous pouvez exécuter un callback au lieu de cet écran. Vérifiez la console pour voir un exemple...",
"success.orderPlaced": "Vous avez passé commande",
"success.paymentTerms": "Conditions de paiement",
"success.title": "Acheteur enregistré",
"success.transactionId": "Identifiant de la transaction",
"validation.fillAllFields": "Veuillez remplir tous les champs obligatoires",
"validation.invalidCountryCode": "Code pays non valide",
"validation.invalidEmail": "Veuillez saisir une adresse électronique valide",
"validation.invalidPhone": "Veuillez saisir un numéro de téléphone valide",
"validation.phoneIsLong": "Le numéro de téléphone est trop long",
"validation.phoneIsShort": "Le numéro de téléphone est trop court",
"validation.wrongOtp": "Le code que vous avez saisi est incorrect. Veuillez réessayer"
};
const i18nResources = {
en: {
translation: en
},
nl: {
translation: nl
},
de: {
translation: de
},
es: {
translation: es
},
fr: {
translation: fr
}
};
class Sprinque {
constructor() {
this.open = async ({
getTokenUrl = '',
token = '',
env = 'sandbox',
lang = 'en',
onBuyerResponse,
onOrderCreated,
order,
buyerId
}) => {
if (onBuyerResponse) SprinqueModal.onBuyerResponse = onBuyerResponse;
if (onOrderCreated) SprinqueModal.onOrderCreated = onOrderCreated;
if (order) SprinqueModal.order = order;
// fetch temporary token
let respData;
if (getTokenUrl) {
const resp = await fetch(`${getTokenUrl}`);
respData = await resp.json();
}
if (respData && respData.access || token) {
// initialized translations
await i18next.init({
lng: lang,
debug: process.env.NODE_ENV === 'development',
resources: i18nResources
});
document.getElementsByTagName('body')[0].insertAdjacentHTML('beforeend', `<sprinque-modal token=${token || respData.access} getTokenUrl=${getTokenUrl} env=${env} ${buyerId && `buyer-id=${buyerId}`} lang=${lang} />`);
window.customElements.get(SPRINQUE_CUSTOM_ELEMENT_NAME) || window.customElements.define(SPRINQUE_CUSTOM_ELEMENT_NAME, SprinqueModal);
}
// Fullstory tracking
if (location.hostname !== 'localhost') {
FullStory.init({
orgId: 'o-1ESJKB-na1'
});
}
};
this.close = () => {
removeSprinqueModal();
};
}
}
const sprinque = new Sprinque();
const open = sprinque.open;
const close = sprinque.close;
export { Sprinque, close, open };