UNPKG

paytm-blink-checkout-vue

Version:

Vue js based implementation for Paytm Blink Checkout JS

306 lines (286 loc) 9.09 kB
var PaytmBlinkCheckoutVue=(function(exports,vueDemi){'use strict';const CONSTANTS = { PROJECT_NAME: 'Paytm Blink Checkout JS', ENV: { PROD: 'PROD', STAGE: 'STAGE' }, HOSTS: { PROD: 'https://securegw.paytm.in', STAGE: 'https://securegw-stage.paytm.in' }, LINKS: { CHECKOUT_JS_URL: '/merchantpgpui/checkoutjs/merchants/' }, ERRORS: { INIT : 'An error during initialization!', INVOKE : 'An error during invoking!', MERCHANT_ID_NOT_FOUND: 'Please provide merchant id!', CHECKOUT_NOT_AVAILABLE: 'Checkout JS library not found. Please make sure you have included checkout js!', INVALID_CHECKOUT_JS_INSTANCE: 'Invalid instance provided!' }, IDS: { CHECKOUT_ELEMENT: 'checkout-wrapper-' } }; // Prefix error with project name Object.keys(CONSTANTS.ERRORS).forEach(errorCode=>{ CONSTANTS.ERRORS[errorCode] = `${CONSTANTS.PROJECT_NAME}: ${CONSTANTS.ERRORS[errorCode]}`; });function isTrue(value) { return typeof value === "boolean" ? value : typeof value === "string" ? value === "true" : false; } function propChangedHandler(newVal, oldVal) { oldVal !== newVal && this.preSetup(); } /** * The component is responsible for setting up Checkout JS library. * It sets the Checkout JS instance and make it available to all its children * component via Provider. It requires config property which is * mandatory is order to initialize Checkout JS library. Additionally openInPopup * prop can also be passed to show checkout in popup or not, by default its * value is true. * The config should be of same format as the Checkout JS library, which * could be checked from this * [link](https://developer.paytm.com/docs/js-checkout/configuration/options/?ref=jsCheckout). * * Example * <CheckoutProvider :config="config" env="PROD" :openInPopup="openInPopup"> * </CheckoutProvider> */ var CheckoutProvider = vueDemi.defineComponent({ name: "CheckoutProvider", data() { return { isScriptLoaded: false, isScriptLoading: false, localConfig: null, }; }, setup() { const localCheckoutJsInstance = vueDemi.ref(null); const elementId = vueDemi.ref( CONSTANTS.IDS.CHECKOUT_ELEMENT + new Date().getTime() ); vueDemi.provide("checkoutJsInstance", localCheckoutJsInstance); vueDemi.provide("elementId", elementId); return { localCheckoutJsInstance, elementId, }; }, props: { config: Object, checkoutJsInstance: Object, openInPopup: Boolean, env: String, }, watch: { config: propChangedHandler, checkoutJsInstance: propChangedHandler, openInPopup: propChangedHandler, }, mounted() { this.preSetup(); }, methods: { preSetup() { const { config, checkoutJsInstance } = this; const merchantId = config && config.merchant && config.merchant.mid; if (!merchantId) { console.error(CONSTANTS.ERRORS.MERCHANT_ID_NOT_FOUND); return; } const prevMerchantId = this.localConfig && this.localConfig.merchant && this.localConfig.merchant.mid; this.localConfig = config; if ( (checkoutJsInstance || this.isScriptLoaded) && prevMerchantId === merchantId ) { this.initializeCheckout(); } else if ( !this.isScriptLoading || (prevMerchantId && merchantId !== prevMerchantId) ) { this.loadCheckoutScript(merchantId); } }, loadCheckoutScript(merchantId) { const env = CONSTANTS.ENV[(this.env || "").toUpperCase()] || CONSTANTS.ENV.PROD; const scriptElement = document.createElement("script"); scriptElement.async = true; scriptElement.src = CONSTANTS.HOSTS[env] + CONSTANTS.LINKS.CHECKOUT_JS_URL.concat(merchantId); scriptElement.type = "application/javascript"; scriptElement.onload = this.setupCheckoutJsOnScriptLoad; scriptElement.onerror = (error) => { console.error(CONSTANTS.ERRORS.FAILED_TO_LOAD_SCRIPT, error); this.isScriptLoading = false; }; document.body.appendChild(scriptElement); this.isScriptLoading = true; }, setupCheckoutJsOnScriptLoad() { const checkoutJsInstance = this.getCheckoutJsObj(); this.isScriptLoading = true; this.isScriptLoaded = false; if (checkoutJsInstance && checkoutJsInstance.onLoad) { checkoutJsInstance.onLoad(() => { this.isScriptLoading = false; this.isScriptLoaded = true; this.initializeCheckout(); }); } else { console.error(CONSTANTS.ERRORS.INVALID_CHECKOUT_JS_INSTANCE); } }, initializeCheckout() { const { openInPopup = true } = this; // Set checkoutJsInstance via shallow copy so that invoke method in // checkout component can be invoked via shallow comparison. const checkoutJsInstance = { ...this.getCheckoutJsObj() }; if ( checkoutJsInstance && checkoutJsInstance.init && checkoutJsInstance.invoke ) { checkoutJsInstance .init({ ...this.config, root: isTrue(openInPopup) ? "" : `#${this.elementId}`, }) .then(() => { this.localCheckoutJsInstance = checkoutJsInstance; }) .catch((error) => { console.error(CONSTANTS.ERRORS.INIT, error); }); } else { console.error(CONSTANTS.ERRORS.INVALID_CHECKOUT_JS_INSTANCE); } }, getCheckoutJsObj() { if (this.checkoutJsInstance) { return this.checkoutJsInstance; } if (window && window.Paytm && window.Paytm.CheckoutJS) { return window.Paytm.CheckoutJS; } console.warn(CONSTANTS.ERRORS.CHECKOUT_NOT_AVAILABLE); return null; }, }, render() { return vueDemi.h( "span", {}, typeof this.$slots.default === 'function' ? this.$slots.default() : this.$slots.default ); } });var Checkout = vueDemi.defineComponent({ name: "Checkout", setup() { const elementId = vueDemi.inject("elementId"); const checkoutJsInstance = vueDemi.inject("checkoutJsInstance"); return { elementId, checkoutJsInstance, }; }, watch: { checkoutJsInstance: function (newVal, oldVal) { oldVal !== newVal && this.invoke(newVal); }, }, mounted() { this.checkoutJsInstance && this.invoke(this.checkoutJsInstance); }, methods: { invoke(checkoutJsInstance) { if (checkoutJsInstance && checkoutJsInstance.invoke) { try { checkoutJsInstance.invoke(); } catch (error) { console.error(CONSTANTS.ERRORS.INVOKE, error); } } }, }, render() { return vueDemi.h( "div", vueDemi.isVue2 ? { attrs: { id: this.elementId, }, } : { id: this.elementId, }, [] ); }, });/** * The higher order component injects Checkout JS instance to the wrapped component * and make it available in the wrapped component props as checkoutJsInstance . * The instance allows to directly interact with CheckoutJs library . * The injected component should be always nested inside CheckoutProvider component. * * Example * * Component that makes use of checkoutJsInstance prop. * export default { * name: "Test", * props: { * checkoutJsInstance: Object * } * }; * * Wrap component in a higher order component which provides checkoutJsInstance prop. * const InjectedCheckout = injectCheckout(Test); * * Render the wrapped component * <CheckoutProvider :config="config"> * <InjectedComponent /> * </CheckoutProvider> * */ function InjectCheckout (WrappedComponent) { const originalProps = WrappedComponent.props || {}; return { setup() { const checkoutJsInstance = vueDemi.inject("checkoutJsInstance"); return { checkoutJsInstance, }; }, render() { return vueDemi.h( WrappedComponent, vueDemi.isVue2 ? { props: { ...this.$props, checkoutJsInstance: this.checkoutJsInstance, }, } : { ...this.$props, checkoutJsInstance: this.checkoutJsInstance, }, typeof this.$slots.default === "function" ? this.$slots.default() : this.$slots.default ); }, props: [...Object.keys(originalProps).filter(prop => prop !== "checkoutJsInstance")], }; }exports.Checkout=Checkout;exports.CheckoutProvider=CheckoutProvider;exports.injectCheckout=InjectCheckout;Object.defineProperty(exports,'__esModule',{value:true});return exports;}({},VueDemi));