UNPKG

@tamara-solution/checkout

Version:

Script will be embedded in merchant's site to checkout. The merchant's don't need to redirect to tamara's site.

233 lines (178 loc) 6.04 kB
import Style from '@/helpers/style' import debug from '@/helpers/debug' import { getType, isFunction } from '@/helpers/type' import { appendHTML, removeElement } from '@/helpers/document-html' import generateFrameElement from '@/helpers/frame-template' import { FrameError, TamaraTypeError } from '@/helpers/frame-error' import { isValidTamaraURL, isLocalhost } from '@/helpers/validate-domain' import FrameEvents from '@/constants/frame-events' import CheckoutEvents from '@/constants/checkout-events' class CheckoutFrame { constructor() { this.config = {} this.eventHandlers = {} this.styles = new Style({}) this.resizeListener = null this.Events = Object.freeze({ ...FrameEvents }) this._listenEventFromIframe() } init(config) { this.config = config || {} const { style: customestyle = {} } = config || {} this.styles = new Style({ ...customestyle }) } checkout(checkoutURL) { this.callListener(this.Events.STARTED, { started: true }) const params = { url: this._getCheckoutURL(checkoutURL), styles: this._getStyle(), loaded: this._callbackLoaded.bind(this), } const { frameElement, iframe, wrapperIframe } = generateFrameElement(params) this.resizeListener = this._recalculateStyle.bind( this, wrapperIframe, iframe ) window.addEventListener('resize', this.resizeListener) appendHTML('body', frameElement) } addEventHandlers(event, handler) { if (this.config.debug) { debug('ADD Event hanlders >>> ', event) } if (getType(handler) !== 'function') { throw new TamaraTypeError('Handler must be a function!') } if (getType(this.eventHandlers[event]) !== 'array') { this.eventHandlers[event] = [] } if (this.config.debug) { debug('Event hanlders >>> Before ADD >>> ', this.eventHandlers) } const foundIndex = this.eventHandlers[event].indexOf(handler) if (foundIndex > -1) { throw new FrameError('The handler is exist already!') } this.eventHandlers[event].push(handler) if (this.config.debug) { debug('Event hanlders >>> After ADDED >>> ', this.eventHandlers) debug('ADD Event hanlders >>> SUCCESS') } } removeEventHandlers(event, handler) { if (this.config.debug) { debug('REMOVE Event hanlders >>> ', event) } if (getType(handler) !== 'function') { throw new TamaraTypeError('Handler must be a function!') } if (getType(this.eventHandlers[event]) !== 'array') { return true } if (this.config.debug) { debug('Event hanlders >>> Before REMOVE >>> ', this.eventHandlers) } const foundIndex = this.eventHandlers[event].indexOf(handler) if (foundIndex > -1) { // Delete an element at foundIndex this.eventHandlers[event].splice(foundIndex, 1) } if (this.config.debug) { debug('Event hanlders >>> After REMOVED >>> ', this.eventHandlers) debug('REMOVE Event hanlders >>> SUCCESS') } } removeAllEventHandlers(event) { if (this.config.debug) { debug('REMOVE_ALL Event hanlders >>> ', event) } if (getType(handler) !== 'function') { throw new TamaraTypeError('Handler must be a function!') } if (getType(this.eventHandlers[event]) !== 'array') { return true } if (this.config.debug) { debug('Event hanlders >>> Before REMOVE_ALL >>> ', this.eventHandlers) } this.eventHandlers[event] = [] if (this.config.debug) { debug('Event hanlders >>> After REMOVED >>> ', this.eventHandlers) debug('REMOVE_ALL Event hanlders >>> SUCCESS') } } callListener(event, data = {}) { const handlers = this.eventHandlers[event] if (this.config.debug) { debug('TRIGGER Event >>> ', event, data) } if (getType(handlers) === 'array' && handlers.length > 0) { handlers.forEach(function (handler) { if (isFunction(handler)) { handler(data) } }) } } _recalculateStyle(wrapperIframe, iframe) { const styles = this._getStyle() const wrapperStyle = styles.wrapper || '' const iframeStyle = styles.iframe || '' wrapperIframe.setAttribute('style', wrapperStyle) iframe.setAttribute('style', iframeStyle) } _getStyle() { return { frame: this.styles.getFrameStyle(), wrapper: this.styles.getWrapperStyle(), iframe: this.styles.getIframeStyle(), background: this.styles.getBackgroundStyle(), } } _getCheckoutURL(checkoutURL) { // Only accept localhost in development mode const isLocalhostURL = isLocalhost(checkoutURL) if (!isValidTamaraURL(checkoutURL) && isLocalhostURL) { throw new FrameError("The URL is not tamara's domain.") } return `${checkoutURL}&checkoutFrame=iframe` } _callbackLoaded() { this.callListener(this.Events.LOADED, { loaded: true }) } _listenEventFromIframe() { const EVENT_MAPPING = { [CheckoutEvents.ORDER_SUCCESS]: this._handleOrderSuccess.bind(this), [CheckoutEvents.ORDER_FAILED]: this._handleOrderFailed.bind(this), [CheckoutEvents.ORDER_CANCELED]: this._handleOrderCanceled.bind(this), } window.addEventListener('message', function (evt) { const { type, event, data } = evt.data || {} if (type === 'tamara_checkout_message') { const handler = EVENT_MAPPING[event] if (isFunction(handler)) { handler(data) } } }) } _handleOrderSuccess(data) { this.callListener(this.Events.SUCCESS, data) this._closeIframe() } _handleOrderFailed(data) { this.callListener(this.Events.FAILED, data) this._closeIframe() } _handleOrderCanceled(data) { this.callListener(this.Events.CANCELED, data) this._closeIframe() } _closeIframe() { removeElement('tamara-checkout-frame') this.callListener(this.Events.CLOSED) window.removeEventListener('resize', this.resizeListener) } } export default CheckoutFrame