Skip to content

Commit 7893f16

Browse files
Add integration intercom This commit copies the content of the integration repo into the "integrations" folder. Original repo: https://github.com/segment-integrations/analytics.js-integration-intercom Readme: https://github.com/segment-integrations/analytics.js-integration-intercom/blob/master/README.md
1 parent ab2ec4d commit 7893f16

File tree

6 files changed

+949
-0
lines changed

6 files changed

+949
-0
lines changed

integrations/intercom/HISTORY.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
2+
3.0.0 / 2017-08-21
3+
==================
4+
5+
* Drop support for stringifying/flattened arrays or objects as requested by Intercom
6+
7+
2.2.3 / 2017-02-16
8+
==================
9+
10+
* Update modules to support IE browsers
11+
12+
2.2.2 / 2017-02-16
13+
==================
14+
15+
* Add option to let customers decide how they would like their custom nested traits to be handled
16+
* Fix unsubscribe bug
17+
* Add special hanlding for Rich Link
18+
19+
2.1.2 / 2017-02-02
20+
==================
21+
22+
* Properly map monthlySpend and revenue for parity with server-side integration
23+
24+
2.1.1 / 2016-09-13
25+
==================
26+
27+
* Fix ie8 compat (#17)
28+
29+
2.1.0 / 2016-08-24
30+
==================
31+
32+
* support hide default launcher
33+
34+
2.0.0 / 2016-06-21
35+
==================
36+
37+
* Remove Duo compatibility
38+
* Add CI setup (coverage, linting, cross-browser compatibility, etc.)
39+
* Update eslint configuration
40+
41+
1.0.5 / 2016-05-07
42+
==================
43+
44+
* Bump Analytics.js core, tester, integration to use Facade 2.x
45+
46+
1.0.4 / 2015-12-23
47+
==================
48+
49+
* deprecate increments
50+
51+
1.0.3 / 2015-06-30
52+
==================
53+
54+
* Replace analytics.js dependency with analytics.js-core
55+
56+
1.0.2 / 2015-06-24
57+
==================
58+
59+
* Bump analytics.js-integration version
60+
61+
1.0.1 / 2015-06-24
62+
==================
63+
64+
* Bump analytics.js-integration version
65+
66+
1.0.0 / 2015-06-09
67+
==================
68+
69+
* Initial commit :sparkles:

integrations/intercom/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# analytics.js-integration-intercom [![Build Status][ci-badge]][ci-link]
2+
3+
Intercom integration for [Analytics.js][].
4+
5+
## License
6+
7+
Released under the [MIT license](LICENSE).
8+
9+
10+
[Analytics.js]: https://segment.com/docs/libraries/analytics.js/
11+
[ci-link]: https://circleci.com/gh/segment-integrations/analytics.js-integration-intercom
12+
[ci-badge]: https://circleci.com/gh/segment-integrations/analytics.js-integration-intercom.svg?style=svg

integrations/intercom/lib/index.js

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
'use strict';
2+
3+
/**
4+
* Module dependencies.
5+
*/
6+
7+
var convertDates = require('@segment/convert-dates');
8+
var defaults = require('@ndhoule/defaults');
9+
var del = require('obj-case').del;
10+
var integration = require('@segment/analytics.js-integration');
11+
var is = require('is');
12+
var extend = require('@ndhoule/extend');
13+
var clone = require('@ndhoule/clone');
14+
var each = require('@ndhoule/each');
15+
var pick = require('@ndhoule/pick');
16+
17+
/**
18+
* Expose `Intercom` integration.
19+
*/
20+
21+
var Intercom = module.exports = integration('Intercom')
22+
.global('Intercom')
23+
.option('activator', '#IntercomDefaultWidget')
24+
.option('appId', '')
25+
.option('richLinkProperties', [])
26+
.tag('<script src="https://widget.intercom.io/widget/{{ appId }}">');
27+
28+
/**
29+
* Initialize.
30+
*
31+
* http://docs.intercom.io/
32+
* http://docs.intercom.io/#IntercomJS
33+
*
34+
* @api public
35+
*/
36+
37+
Intercom.prototype.initialize = function() {
38+
// Shim out the Intercom library.
39+
window.Intercom = function() {
40+
window.Intercom.q.push(arguments);
41+
};
42+
window.Intercom.q = [];
43+
44+
this.load(this.ready);
45+
};
46+
47+
/**
48+
* Loaded?
49+
*
50+
* @api private
51+
* @return {boolean}
52+
*/
53+
54+
Intercom.prototype.loaded = function() {
55+
return typeof window.Intercom === 'function';
56+
};
57+
58+
/**
59+
* Page.
60+
*
61+
* @api public
62+
* @param {Page} page
63+
*/
64+
65+
Intercom.prototype.page = function(page) {
66+
var integrationSettings = page.options(this.name);
67+
this.bootOrUpdate({}, integrationSettings);
68+
};
69+
70+
/**
71+
* Identify.
72+
*
73+
* http://docs.intercom.io/#IntercomJS
74+
*
75+
* @api public
76+
* @param {Identify} identify
77+
*/
78+
79+
Intercom.prototype.identify = function(identify) {
80+
var traits = identify.traits({ userId: 'user_id' });
81+
var integrationSettings = identify.options(this.name);
82+
var companyCreated = identify.companyCreated();
83+
var created = identify.created();
84+
var name = identify.name();
85+
var id = identify.userId();
86+
var group = this.analytics.group();
87+
var settings = this.options;
88+
89+
if (!id && !identify.email()) {
90+
return;
91+
}
92+
93+
// intercom requires `company` to be an object. default it with group traits
94+
// so that we guarantee an `id` is there, since they require it
95+
if (traits.company !== null && !is.object(traits.company)) {
96+
delete traits.company;
97+
}
98+
99+
if (traits.company) {
100+
defaults(traits.company, group.traits());
101+
}
102+
103+
// name
104+
if (name) traits.name = name;
105+
106+
// handle dates
107+
if (created) {
108+
del(traits, 'created');
109+
del(traits, 'createdAt');
110+
traits.created_at = created;
111+
}
112+
113+
if (companyCreated) {
114+
del(traits.company, 'created');
115+
del(traits.company, 'createdAt');
116+
traits.company.created_at = companyCreated;
117+
}
118+
119+
// convert dates
120+
traits = convertDates(traits, formatDate);
121+
122+
// format nested custom traits
123+
traits = formatNestedCustomTraits(traits, settings);
124+
125+
// handle options
126+
if (integrationSettings.userHash) traits.user_hash = integrationSettings.userHash;
127+
if (integrationSettings.user_hash) traits.user_hash = integrationSettings.user_hash;
128+
129+
this.bootOrUpdate(traits, integrationSettings);
130+
};
131+
132+
/**
133+
* Group.
134+
*
135+
* @api public
136+
* @param {Group} group
137+
*/
138+
139+
Intercom.prototype.group = function(group) {
140+
var settings = this.options;
141+
// using .traits here since group.properties() doesn't take alias object
142+
var props = group.traits({
143+
createdAt: 'created',
144+
created: 'created_at',
145+
monthlySpend: 'monthly_spend'
146+
});
147+
props = convertDates(props, formatDate);
148+
var id = group.groupId();
149+
if (id) props.id = id;
150+
var integrationSettings = group.options(this.name);
151+
152+
// format nested custom traits
153+
props = formatNestedCustomTraits(props, settings);
154+
155+
var traits = extend({ company: props }, hideDefaultLauncher(integrationSettings));
156+
157+
api('update', traits);
158+
};
159+
160+
/**
161+
* Track.
162+
*
163+
* @api public
164+
* @param {Track} track
165+
*/
166+
167+
Intercom.prototype.track = function(track) {
168+
var settings = this.options;
169+
var props = track.properties();
170+
var revenue = track.revenue();
171+
if (revenue) {
172+
var revenueData = {
173+
// Intercom requests value in cents
174+
price: {
175+
amount: revenue * 100,
176+
currency: track.currency() // fallsback on 'USD'
177+
}
178+
};
179+
}
180+
181+
// format Nested custom traits
182+
props = formatNestedCustomTraits(props, settings);
183+
184+
props = extend(props, revenueData);
185+
del(props, 'revenue');
186+
del(props, 'currency');
187+
188+
api('trackEvent', track.event(), props);
189+
};
190+
191+
/**
192+
* Boots or updates, as appropriate.
193+
*
194+
* @api private
195+
* @param {Object} options
196+
*/
197+
198+
Intercom.prototype.bootOrUpdate = function(options, integrationSettings) {
199+
options = options || {};
200+
var method = this.booted === true ? 'update' : 'boot';
201+
var activator = this.options.activator;
202+
options.app_id = this.options.appId;
203+
204+
// Intercom, will force the widget to appear if the selector is
205+
// #IntercomDefaultWidget so no need to check inbox, just need to check that
206+
// the selector isn't #IntercomDefaultWidget.
207+
if (activator !== '#IntercomDefaultWidget') {
208+
options.widget = { activator: activator };
209+
}
210+
// Check for selective showing of messenger option
211+
options = extend(options, hideDefaultLauncher(integrationSettings));
212+
213+
api(method, options);
214+
this.booted = true;
215+
};
216+
217+
/**
218+
* Format a date to Intercom's liking.
219+
*
220+
* @api private
221+
* @param {Date} date
222+
* @return {number}
223+
*/
224+
225+
function formatDate(date) {
226+
return Math.floor(date / 1000);
227+
}
228+
229+
/**
230+
* Flatten selectively based on your settings. You can either stringify, flatten, or drop the properties.
231+
* Intercom rejects nested objects so you must choose a method.
232+
*
233+
* @param {Object} obj
234+
* @param {Object} settings
235+
* @return {Object} ret
236+
* @api private
237+
*/
238+
239+
function formatNestedCustomTraits(obj, settings) {
240+
var richLinkProperties = settings.richLinkProperties;
241+
var basicIntercomTraits = [
242+
'companies',
243+
'company',
244+
'created_at',
245+
'created',
246+
'custom_attributes',
247+
'company_id',
248+
'id',
249+
'name',
250+
'monthly_spend',
251+
'plan',
252+
'remote_created_at',
253+
'remove',
254+
'user_id',
255+
'email'
256+
];
257+
258+
// add rich link object to semantic traits so that it's not altered by the default method and
259+
// is passed to intercom as a nested object: https://developers.intercom.com/reference#event-metadata-types
260+
var semanticTraits = basicIntercomTraits.concat(richLinkProperties);
261+
262+
// clone traits so we don't modify the original object
263+
var customTraits = clone(obj);
264+
265+
// filter out semanticTraits so that we only format custom nested traits
266+
each(function(trait) {
267+
del(customTraits, trait);
268+
}, semanticTraits);
269+
270+
// create object without custom traits to merge with formatted custom traits in the end
271+
var standardTraits = pick(semanticTraits, obj);
272+
273+
// drop any arrays or objects
274+
var supportedTraits = {};
275+
each(function(value, key) {
276+
if (!is.object(value) && !is.array(value)) supportedTraits[key] = value;
277+
}, customTraits);
278+
279+
// combine all the traits
280+
return extend(supportedTraits, standardTraits);
281+
}
282+
283+
/**
284+
* Push a call onto the Intercom queue.
285+
*
286+
* @api private
287+
*/
288+
289+
function api() {
290+
window.Intercom.apply(window.Intercom, arguments);
291+
}
292+
293+
/**
294+
* Selectively hide messenger
295+
* https://docs.intercom.io/configure-intercom-for-your-product-or-site/customize-the-intercom-messenger/customize-the-intercom-messenger-technical#show-the-intercom-messenger-to-selected-users-for-web-
296+
* @param {Object} options
297+
* @return {Object} ret
298+
* @api private
299+
*/
300+
301+
function hideDefaultLauncher(options) {
302+
var ret = {};
303+
var setting = options.hideDefaultLauncher;
304+
if (setting === undefined || typeof setting !== 'boolean') return ret;
305+
ret.hide_default_launcher= setting;
306+
return ret;
307+
}

0 commit comments

Comments
 (0)