Skip to content

Commit

Permalink
Merge pull request #467 from recurly/events-meta
Browse files Browse the repository at this point in the history
Report metadata
  • Loading branch information
gla7 authored Aug 8, 2018
2 parents 40d4ca9 + d0da1db commit 83e45d7
Show file tree
Hide file tree
Showing 12 changed files with 353 additions and 230 deletions.
68 changes: 0 additions & 68 deletions ANALYTICS.md

This file was deleted.

24 changes: 17 additions & 7 deletions lib/recurly.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {factory as Frame} from './recurly/frame';
import {factory as PayPal} from './recurly/paypal';
import {deprecated as deprecatedPaypal} from './recurly/paypal/strategy/direct';
import {Bus} from './recurly/bus';
import {EventDispatcher} from './recurly/event';
import {Reporter} from './recurly/reporter';
import {Fraud} from './recurly/fraud';
import {HostedFields, FIELD_TYPES} from './recurly/hosted-fields';
import {Request} from './recurly/request';
Expand Down Expand Up @@ -109,16 +109,16 @@ export class Recurly extends Emitter {
token: bankAccount.token.bind(this),
bankInfo: bankAccount.bankInfo.bind(this)
};
this.event = new EventDispatcher({ recurly: this });
this.reporter = new Reporter({ recurly: this });
this.request = new Request({ recurly: this });

// @deprecated -- Old method of instantiating single-subscription Pricing
this.Pricing = () => new SubscriptionPricing(this);
this.Pricing.Checkout = () => new CheckoutPricing(this);
this.Pricing.Subscription = () => new SubscriptionPricing(this);

this.once('ready', () => this.event.send({ name: 'ready' }));
this.bindDispatchedEvents();
this.once('ready', () => this.report('ready'));
this.bindReporting();
}

/**
Expand Down Expand Up @@ -232,7 +232,7 @@ export class Recurly extends Emitter {
if (!this.configured) {
this.configured = true;
this.emit('configured');
if (this.event) this.event.send({ name: 'configured' });
this.report('configured');
}
}

Expand Down Expand Up @@ -292,19 +292,29 @@ export class Recurly extends Emitter {
}
}

/**
* Reports an event to the Reporter if it is available
*
* @private
*/
report (...args) {
if (!this.reporter) return;
this.reporter.send(...args);
}

/**
* Binds important events to the EventDispatcher
*
* @private
*/
bindDispatchedEvents () {
bindReporting () {
if (!this.isParent) return;
['focus', 'blur'].forEach(eventName => {
this.on(`hostedField:${eventName}`, ({ type }) => {
const state = this.hostedFields.state[type];
let meta = pick(state, ['valid', 'empty']);
if (state.brand) meta.brand = state.brand;
this.event.send({ name: `hosted-field:${eventName}`, meta });
this.report(`hosted-field:${eventName}`, meta);
});
});
}
Expand Down
10 changes: 5 additions & 5 deletions lib/recurly/errors.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {EventDispatcher} from './event';
import {Reporter} from './reporter';

const BASE_URL = 'https://dev.recurly.com/docs/recurly-js-';
const ERRORS = [
Expand Down Expand Up @@ -220,7 +220,7 @@ class ErrorDirectory {
* @param {String} code
* @param {Object} [context] arbitrary error property dictionary
* @param {Object} [options]
* @param {EventDispatcher} [options.reporter] EventDispatcher instance to report errors
* @param {Reporter} [options.reporter] Reporter instance to report errors
* @return {RecurlyError}
* @throws {Error} if the requested error is not in the directory
*/
Expand Down Expand Up @@ -251,7 +251,7 @@ function recurlyErrorFactory (definition) {
* @param {String} message error message
* @param {Object} context suplementary error data
* @param {Object} [options]
* @param {EventDispatcher} [options.reporter] EventDispatcher instance used to report an error
* @param {Reporter} [options.reporter] Reporter instance used to report an error
* @param {String} [help] documentation reference
*/
function RecurlyError (context = {}, options = {}) {
Expand All @@ -272,13 +272,13 @@ function recurlyErrorFactory (definition) {
this.message += ` (need help? ${this.help})`;
}

if (this.reporter instanceof EventDispatcher) {
if (this.reporter instanceof Reporter) {
let type = 'client';
if (this.classification) type += `:${this.classification}`;

// Warning: any errors that occur in this code path risk
// a stack overflow if they include a reporter
this.reporter.send({ name: 'error', type });
this.reporter.send('error', { type });
}
}

Expand Down
75 changes: 43 additions & 32 deletions lib/recurly/pricing/checkout/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import clone from 'component-clone';
import find from 'component-find';
import intersection from 'intersect';
import isEmpty from 'lodash.isempty';
Expand All @@ -23,6 +24,7 @@ export default class CheckoutPricing extends Pricing {
constructor (...args) {
super(...args);
this.debug = debug;
this.recurly.report('pricing:checkout:create');
}

reset () {
Expand Down Expand Up @@ -109,11 +111,7 @@ export default class CheckoutPricing extends Pricing {
}))
// Eject gift cards on currency change
.then(() => this.giftCard(null))
.then(() => {
debug('set.currency');
this.emit('set.currency', code);
resolve(code);
});
.then(() => this.resolveAndEmit('set.currency', code, resolve));
}, this);
}

Expand Down Expand Up @@ -171,9 +169,7 @@ export default class CheckoutPricing extends Pricing {
subscription.on('set.plan', emitSubscriptionSetter('plan'));
subscription.on('set.addon', emitSubscriptionSetter('addon'));
this.items.subscriptions.push(new EmbeddedSubscriptionPricing(subscription, this));
debug('set.subscription');
this.emit('set.subscription', subscription);
resolve(subscription);
this.resolveAndEmit('set.subscription', subscription, resolve, { copy: false });
}

// Removes any subscription coupons and gift cards
Expand Down Expand Up @@ -238,47 +234,47 @@ export default class CheckoutPricing extends Pricing {
this.items.adjustments.push(adjustment);
}

debug('set.adjustment');
this.emit('set.adjustment', adjustment);
resolve(adjustment);
this.resolveAndEmit('set.adjustment', adjustment, resolve);
}, this);
}

/**
* Updates coupon. Manages a single coupon on the item set, unsetting any exisitng
* coupon
*
* `set.coupon` is emitted when a valid coupon is set
* `unset.coupon` is emitted when an existing valid coupon is removed
* `error.coupon` is emitted when the requested coupon is invalid
*
* @param {String} couponCode
* @return {PricingPromise}
* @public
*/
coupon (couponCode) {
const unset = () => {
debug('unset.coupon');
delete this.items.coupon;
this.emit('unset.coupon');
};
if (~this.couponCodes.indexOf(couponCode)) {
return new PricingPromise(resolve => resolve(clone(this.items.coupon)), this);
}

return new PricingPromise(resolve => resolve(), this)
.then(() => {
if (this.items.coupon) return this.remove({ coupon: this.items.coupon.code });
if (!this.items.coupon) return;
const priorCoupon = clone(this.items.coupon);
debug('unset.coupon');
return this.remove({ coupon: priorCoupon.code })
.then(() => {
this.emit('unset.coupon', priorCoupon);
});
})
.then(() => new PricingPromise((resolve, reject) => {
// A blank coupon is handled as ok
if (!couponCode) {
unset();
return resolve();
}
if (!couponCode) return resolve();

this.recurly.coupon({ plans: this.subscriptionPlanCodes, coupon: couponCode }, (err, coupon) => {
if (err && err.code === 'not-found') unset();
if (err) {
return this.error(err, reject, 'coupon');
} else {
debug('set.coupon');
this.items.coupon = coupon;
this.emit('set.coupon', coupon);
resolve(coupon);
this.resolveAndEmit('set.coupon', coupon, resolve);
}
});
}));
Expand Down Expand Up @@ -352,10 +348,8 @@ export default class CheckoutPricing extends Pricing {
if (this.items.currency !== giftCard.currency){
return this.error(errors('gift-card-currency-mismatch'), reject, 'giftCard');
} else {
debug('set.giftCard');
this.items.giftCard = giftCard;
this.emit('set.giftCard', giftCard);
resolve(giftCard);
this.resolveAndEmit('set.giftCard', giftCard, resolve);
}
}
});
Expand Down Expand Up @@ -441,9 +435,26 @@ export default class CheckoutPricing extends Pricing {
*
* @protected
*/
bindDispatchedEvents () {
super.bindDispatchedEvents();
const send = (...args) => this.recurly.event && this.recurly.event.send(...args);
this.on('set.subscription', subscription => send({ name: 'pricing:set:subscription' }));
bindReporting () {
super.bindReporting('pricing:checkout');
const report = (...args) => this.recurly.report(...args);
this.on('attached', () => report('pricing:checkout:attached'));
this.on('set.subscription', subscription => report('pricing:checkout:set:subscription'));
this.on('change:external', price => report('pricing:checkout:change', {
price: {
couponCodes: this.couponCodes,
currency: this.currencyCode,
discount: price.now.discount,
giftCard: price.now.giftCard,
items: price.now.items.map(item => ({
type: item.type,
amount: item.amount,
quantity: item.quantity,
})),
taxes: price.now.taxes,
total: price.now.total,
totalNext: price.next.total
}
}));
}
}
Loading

0 comments on commit 83e45d7

Please sign in to comment.