UNPKG

sprinque-js-sdk-wip

Version:

UI kit to implement Pay by Invoice with Sprinque

2,174 lines 81 kB
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">&times;</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 };