'use strict';
var frameService = require('../../frame-service/external');
var BraintreeError = require('../../lib/error');
var VERSION = require('package.version');
var constants = require('../shared/constants');
var INTEGRATION_TIMEOUT_MS = require('../../lib/constants').INTEGRATION_TIMEOUT_MS;
var analytics = require('../../lib/analytics');
/**
* @typedef {object} PayPal~tokenizePayload
* @property {string} nonce The payment method nonce
* @property {string} type Always <code>PayPalAccount</code>
* @property {object} details Additional PayPal account details
* @property {string} details.email User's email address
* @property {string} details.firstName User's given name
* @property {string} details.lastName User's surname
* @property {string} details.payerId User's PayPal payerId
* @property {?string} details.countryCode User's 2 character country code
* @property {?string} details.phone User's phone number (e.g. 555-867-5309)
* @property {?object} details.shippingAddress User's shipping address details
* @property {string} details.shippingAddress.recipientName Recipient of postage
* @property {string} details.shippingAddress.line1 Street number and name
* @property {string} details.shippingAddress.line2 Extended address
* @property {string} details.shippingAddress.city City or locality
* @property {string} details.shippingAddress.state State or region
* @property {string} details.shippingAddress.postalCode Postal code
* @property {string} details.shippingAddress.countryCodeAlpha2 2 character country code (e.g. US)
*/
/**
* @typedef {object} PayPal~tokenizeReturn
* @property {Function} close A handle to close the PayPal checkout flow
*/
/**
* @class
* @param {module:braintree/paypal~createOptions} options see {@link module:braintree/paypal.create|paypal.create}
* @classdesc This class represents a PayPal component. Instances of this class have methods for launching auth dialogs and other programmatic interactions with the PayPal component.
*/
function PayPal(options) {
this._options = options;
this._assetsUrl = options.client.getConfiguration().gatewayConfiguration.assetsUrl + '/web/' + VERSION + '/html/';
this._authorizationInProgress = false;
}
PayPal.prototype._initialize = function (callback) {
var options = this._options;
var failureTimeout = setTimeout(function () {
analytics.sendEvent(options.client, 'web.paypal.load.timed-out');
}, INTEGRATION_TIMEOUT_MS);
frameService.create(
this._options,
{
name: constants.LANDING_FRAME_NAME,
url: this._assetsUrl + 'paypal-landing-frame.html'
},
function (service) {
this._frameService = service;
clearTimeout(failureTimeout);
analytics.sendEvent(options.client, 'web.paypal.load.succeeded');
callback();
}.bind(this)
);
};
/**
* Launch the PayPal login flow, returning a nonce payload
* @public
* @param {errback} errback The second argument, <code>data</code>, is a {@link PayPal~tokenizePayload|tokenizePayload}
* @returns {PayPal~tokenizeReturn} A handle to close the PayPal checkout frame
*/
PayPal.prototype.tokenize = function (errback) { //eslint-disable-line
var client = this._options.client;
if (this._authorizationInProgress) {
analytics.sendEvent(client, 'web.paypal.tokenization.error.already-opened');
errback(new BraintreeError({
type: BraintreeError.types.MERCHANT,
message: 'Another tokenization request is active'
}));
} else {
this._authorizationInProgress = true;
analytics.sendEvent(client, 'web.paypal.tokenization.opened');
this._frameService.open(function (err) {
if (err) {
if (err.message === constants.FRAME_CLOSED_ERROR_MESSAGE) {
analytics.sendEvent(client, 'web.paypal.tokenization.closed.by-user');
} else {
// TODO: consider sending a more explicit error to analytics
analytics.sendEvent(client, 'web.paypal.tokenization.failed');
}
} else {
analytics.sendEvent(client, 'web.paypal.tokenization.success');
}
this._authorizationInProgress = false;
errback.apply(null, arguments);
}.bind(this));
}
return {
close: function () {
analytics.sendEvent(client, 'web.paypal.tokenization.closed.by-merchant');
this._frameService.close();
}.bind(this)
};
};
/**
* Cleanly tear down anything set up by {@link module:braintree/paypal.create|create}
* @public
* @param {errorCallback} errback An errback
* @returns {void}
*/
PayPal.prototype.teardown = function (errback) {
this._frameService.teardown();
analytics.sendEvent(this._options.client, 'web.paypal.teardown-completed');
errback();
};
module.exports = PayPal;