@segment/analytics-browser-actions-intercom 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,460 @@
1
+ import { Analytics, Context } from '@segment/analytics-next'
2
+ import { Subscription } from '@segment/browser-destination-runtime'
3
+ import intercomDestination, { destination } from '../../index'
4
+ import { convertDateToUnix } from '../../utils'
5
+
6
+ const subscriptions: Subscription[] = [
7
+ {
8
+ partnerAction: 'identifyUser',
9
+ name: 'Show',
10
+ enabled: true,
11
+ subscribe: 'type = "identify" or "page"',
12
+ mapping: {
13
+ user_id: { '@path': '$.userId' },
14
+ custom_traits: {
15
+ major: {
16
+ '@path': '$.traits.major'
17
+ },
18
+ school: {
19
+ '@path': '$.traits.school'
20
+ }
21
+ },
22
+ name: { '@path': '$.traits.name' },
23
+ email: { '@path': '$.traits.email' },
24
+ phone: { '@path': '$.traits.phone' },
25
+ unsubscribed_from_emails: { '@path': '$.traits.unsubscribedFromEmails' },
26
+ created_at: {
27
+ '@if': {
28
+ exists: { '@path': '$.traits.createdAt' },
29
+ then: { '@path': '$.traits.createdAt' },
30
+ else: { '@path': '$.traits.created_at' }
31
+ }
32
+ },
33
+ language_override: { '@path': '$.traits.languageOverride' },
34
+ user_hash: {
35
+ '@if': {
36
+ exists: { '@path': '$.context.Intercom.user_hash' },
37
+ then: { '@path': '$.context.Intercom.user_hash' },
38
+ else: { '@path': '$.context.Intercom.userHash' }
39
+ }
40
+ },
41
+ hide_default_launcher: {
42
+ '@if': {
43
+ exists: { '@path': '$.context.Intercom.hideDefaultLauncher' },
44
+ then: { '@path': '$.context.Intercom.hideDefaultLauncher' },
45
+ else: { '@path': '$.context.Intercom.hide_default_launcher' }
46
+ }
47
+ },
48
+ avatar_image_url: { '@path': '$.traits.avatar' },
49
+ company: {
50
+ company_id: { '@path': '$.traits.company.id' },
51
+ name: { '@path': '$.traits.company.name' },
52
+ plan: { '@path': '$.traits.company.plan' },
53
+ monthly_spend: { '@path': '$.traits.company.monthlySpend' },
54
+ created_at: {
55
+ '@if': {
56
+ exists: { '@path': '$.traits.company.createdAt' },
57
+ then: { '@path': '$.traits.company.createdAt' },
58
+ else: { '@path': '$.traits.company.created_at' }
59
+ }
60
+ },
61
+ size: { '@path': '$.traits.company.size' },
62
+ website: { '@path': '$.traits.company.website' },
63
+ industry: { '@path': '$.traits.company.industry' },
64
+ company_custom_traits: {
65
+ city: {
66
+ '@path': '$.traits.company.city'
67
+ },
68
+ tech: {
69
+ '@path': '$.traits.company.tech'
70
+ }
71
+ }
72
+ },
73
+ companies: {
74
+ '@arrayPath': [
75
+ '$.traits.companies',
76
+ {
77
+ company_id: { '@path': '$.id' },
78
+ name: { '@path': '$.name' },
79
+ plan: { '@path': '$.plan' },
80
+ monthly_spend: { '@path': '$.monthlySpend' },
81
+ created_at: {
82
+ '@if': {
83
+ exists: { '@path': '$.createdAt' },
84
+ then: { '@path': '$.createdAt' },
85
+ else: { '@path': '$.created_at' }
86
+ }
87
+ },
88
+ size: { '@path': '$.size' },
89
+ website: { '@path': '$.website' },
90
+ industry: { '@path': '$.industry' },
91
+ company_custom_traits: {
92
+ city: {
93
+ '@path': '$.city'
94
+ },
95
+ tech: {
96
+ '@path': '$.tech'
97
+ }
98
+ }
99
+ }
100
+ ]
101
+ }
102
+ }
103
+ }
104
+ ]
105
+
106
+ describe('Intercom.update (user)', () => {
107
+ const settings = {
108
+ appId: 'superSecretAppID',
109
+ activator: '#IntercomDefaultWidget'
110
+ }
111
+
112
+ let mockIntercom: jest.Mock<any, any>
113
+ let identifyUser: any
114
+ beforeEach(async () => {
115
+ jest.restoreAllMocks()
116
+
117
+ const [identifyUserPlugin] = await intercomDestination({
118
+ ...settings,
119
+ subscriptions
120
+ })
121
+ identifyUser = identifyUserPlugin
122
+
123
+ mockIntercom = jest.fn()
124
+ jest.spyOn(destination, 'initialize').mockImplementation(() => {
125
+ const mockedWithProps = Object.assign(mockIntercom as any, settings)
126
+ return Promise.resolve(mockedWithProps)
127
+ })
128
+ await identifyUser.load(Context.system(), {} as Analytics)
129
+ })
130
+
131
+ test('sends an id and traits', async () => {
132
+ const context = new Context({
133
+ type: 'identify',
134
+ userId: 'id',
135
+ traits: {
136
+ email: 'italo@gmail.com'
137
+ }
138
+ })
139
+
140
+ await identifyUser.identify?.(context)
141
+
142
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
143
+ user_id: 'id',
144
+ email: 'italo@gmail.com'
145
+ })
146
+ })
147
+
148
+ test('sends a user name', async () => {
149
+ const context = new Context({
150
+ type: 'identify',
151
+ userId: 'id',
152
+ traits: {
153
+ email: 'italo@gmail.com',
154
+ name: 'italo ferreira'
155
+ }
156
+ })
157
+
158
+ await identifyUser.identify?.(context)
159
+
160
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
161
+ user_id: 'id',
162
+ email: 'italo@gmail.com',
163
+ name: 'italo ferreira'
164
+ })
165
+ })
166
+
167
+ test('sends custom traits', async () => {
168
+ const context = new Context({
169
+ type: 'identify',
170
+ userId: 'id',
171
+ traits: {
172
+ shortboarder: true,
173
+ major: 'cs'
174
+ }
175
+ })
176
+
177
+ await identifyUser.identify?.(context)
178
+
179
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
180
+ user_id: 'id',
181
+ major: 'cs'
182
+ })
183
+ })
184
+
185
+ test('drops custom arrays or objects from traits ', async () => {
186
+ const context = new Context({
187
+ type: 'identify',
188
+ userId: 'id',
189
+ traits: {
190
+ phone: '0000000',
191
+ dropMe: ['i', 'will', 'be', 'dropped'],
192
+ objDrop: {
193
+ foo: 'bar'
194
+ },
195
+ company: {
196
+ id: 'twilio',
197
+ dropMe: ['i', 'will', 'be', 'dropped'],
198
+ objDrop: {
199
+ foo: 'bar'
200
+ }
201
+ },
202
+ companies: [
203
+ {
204
+ id: 'segment',
205
+ dropMe: ['i', 'will', 'be', 'dropped'],
206
+ objDrop: {
207
+ foo: 'bar'
208
+ }
209
+ }
210
+ ]
211
+ }
212
+ })
213
+
214
+ await identifyUser.identify?.(context)
215
+
216
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
217
+ user_id: 'id',
218
+ phone: '0000000',
219
+ company: {
220
+ company_id: 'twilio'
221
+ },
222
+ companies: [
223
+ {
224
+ company_id: 'segment'
225
+ }
226
+ ]
227
+ })
228
+ })
229
+
230
+ test('converts dates', async () => {
231
+ const date = new Date()
232
+ const isoDate = date.toISOString()
233
+ const unixDate = convertDateToUnix(isoDate)
234
+
235
+ const context = new Context({
236
+ type: 'identify',
237
+ userId: 'id',
238
+ traits: {
239
+ createdAt: isoDate,
240
+ company: {
241
+ id: 'twilio',
242
+ createdAt: isoDate
243
+ },
244
+ companies: [
245
+ {
246
+ id: 'segment',
247
+ createdAt: isoDate
248
+ }
249
+ ]
250
+ }
251
+ })
252
+
253
+ await identifyUser.identify?.(context)
254
+
255
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
256
+ user_id: 'id',
257
+ created_at: unixDate,
258
+ company: {
259
+ company_id: 'twilio',
260
+ created_at: unixDate
261
+ },
262
+ companies: [
263
+ {
264
+ company_id: 'segment',
265
+ created_at: unixDate
266
+ }
267
+ ]
268
+ })
269
+ })
270
+
271
+ test('accepts camel/snake case for created_at', async () => {
272
+ const date = new Date()
273
+ const isoDate = date.toISOString()
274
+ const unixDate = convertDateToUnix(isoDate)
275
+
276
+ const context = new Context({
277
+ type: 'identify',
278
+ userId: 'id',
279
+ traits: {
280
+ created_at: isoDate,
281
+ company: {
282
+ id: 'twilio',
283
+ created_at: isoDate
284
+ },
285
+ companies: [
286
+ {
287
+ id: 'segment',
288
+ created_at: isoDate
289
+ }
290
+ ]
291
+ }
292
+ })
293
+
294
+ await identifyUser.identify?.(context)
295
+
296
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
297
+ user_id: 'id',
298
+ created_at: unixDate,
299
+ company: {
300
+ company_id: 'twilio',
301
+ created_at: unixDate
302
+ },
303
+ companies: [
304
+ {
305
+ company_id: 'segment',
306
+ created_at: unixDate
307
+ }
308
+ ]
309
+ })
310
+ })
311
+
312
+ test('avatar works', async () => {
313
+ const context = new Context({
314
+ type: 'identify',
315
+ userId: 'id',
316
+ traits: {
317
+ avatar: 'someurl'
318
+ }
319
+ })
320
+
321
+ await identifyUser.identify?.(context)
322
+
323
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
324
+ user_id: 'id',
325
+ avatar: {
326
+ image_url: 'someurl',
327
+ type: 'avatar'
328
+ }
329
+ })
330
+ })
331
+
332
+ test('allows passing a user hash', async () => {
333
+ const context = new Context({
334
+ type: 'identify',
335
+ userId: 'id',
336
+ traits: {},
337
+ context: {
338
+ Intercom: {
339
+ user_hash: 'x'
340
+ }
341
+ }
342
+ })
343
+
344
+ await identifyUser.identify?.(context)
345
+
346
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
347
+ user_id: 'id',
348
+ user_hash: 'x'
349
+ })
350
+ })
351
+
352
+ test('accepts snake/camel case for user_hash', async () => {
353
+ const context = new Context({
354
+ type: 'identify',
355
+ userId: 'id',
356
+ traits: {},
357
+ context: {
358
+ Intercom: {
359
+ userHash: 'x'
360
+ }
361
+ }
362
+ })
363
+
364
+ await identifyUser.identify?.(context)
365
+
366
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
367
+ user_id: 'id',
368
+ user_hash: 'x'
369
+ })
370
+ })
371
+ })
372
+
373
+ describe('Intercom.update (user) widget options', () => {
374
+ const settings = {
375
+ appId: 'superSecretAppID',
376
+ activator: '#customWidget'
377
+ }
378
+
379
+ let mockIntercom: jest.Mock<any, any>
380
+ let identifyUser: any
381
+ beforeEach(async () => {
382
+ jest.restoreAllMocks()
383
+
384
+ const [identifyUserPlugin] = await intercomDestination({
385
+ ...settings,
386
+ subscriptions
387
+ })
388
+ identifyUser = identifyUserPlugin
389
+
390
+ mockIntercom = jest.fn()
391
+ jest.spyOn(destination, 'initialize').mockImplementation(() => {
392
+ const mockedWithProps = Object.assign(mockIntercom as any, settings)
393
+ return Promise.resolve(mockedWithProps)
394
+ })
395
+ await identifyUser.load(Context.system(), {} as Analytics)
396
+ })
397
+
398
+ test('sets activator if activator is not #IntercomDefaultWidget', async () => {
399
+ const context = new Context({
400
+ type: 'identify',
401
+ userId: 'id',
402
+ traits: {}
403
+ })
404
+
405
+ await identifyUser.identify?.(context)
406
+
407
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
408
+ user_id: 'id',
409
+ widget: {
410
+ activator: '#customWidget'
411
+ }
412
+ })
413
+ })
414
+
415
+ test('should set hide_default_launcher if the setting is there', async () => {
416
+ const context = new Context({
417
+ type: 'identify',
418
+ userId: 'id',
419
+ traits: {},
420
+ context: {
421
+ Intercom: {
422
+ hideDefaultLauncher: true
423
+ }
424
+ }
425
+ })
426
+
427
+ await identifyUser.identify?.(context)
428
+
429
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
430
+ user_id: 'id',
431
+ hide_default_launcher: true,
432
+ widget: {
433
+ activator: '#customWidget'
434
+ }
435
+ })
436
+ })
437
+
438
+ test('accepts snake/camel case for hide_default_launcher', async () => {
439
+ const context = new Context({
440
+ type: 'identify',
441
+ userId: 'id',
442
+ traits: {},
443
+ context: {
444
+ Intercom: {
445
+ hide_default_launcher: true
446
+ }
447
+ }
448
+ })
449
+
450
+ await identifyUser.identify?.(context)
451
+
452
+ expect(mockIntercom).toHaveBeenCalledWith('update', {
453
+ user_id: 'id',
454
+ hide_default_launcher: true,
455
+ widget: {
456
+ activator: '#customWidget'
457
+ }
458
+ })
459
+ })
460
+ })
@@ -0,0 +1,136 @@
1
+ // Generated file. DO NOT MODIFY IT BY HAND.
2
+
3
+ export interface Payload {
4
+ /**
5
+ * A unique identifier for the user.
6
+ */
7
+ user_id?: string
8
+ /**
9
+ * The user's custom attributes.
10
+ */
11
+ custom_traits?: {
12
+ [k: string]: unknown
13
+ }
14
+ /**
15
+ * The user's name.
16
+ */
17
+ name?: string
18
+ /**
19
+ * The user's phone number.
20
+ */
21
+ phone?: string
22
+ /**
23
+ * The user's email unsubscribe status.
24
+ */
25
+ unsubscribed_from_emails?: boolean
26
+ /**
27
+ * The user's messenger language (instead of relying on browser language settings).
28
+ */
29
+ language_override?: string
30
+ /**
31
+ * The user's email address.
32
+ */
33
+ email?: string
34
+ /**
35
+ * The time the user was created in your system.
36
+ */
37
+ created_at?: string | number
38
+ /**
39
+ * The URL for the user's avatar/profile image.
40
+ */
41
+ avatar_image_url?: string
42
+ /**
43
+ * The user hash used for identity verification. See [Intercom docs](https://www.intercom.com/help/en/articles/183-enable-identity-verification-for-web-and-mobile) for more information on how to set this field.
44
+ */
45
+ user_hash?: string
46
+ /**
47
+ * The user's company.
48
+ */
49
+ company?: {
50
+ /**
51
+ * The unique identifier of the company.
52
+ */
53
+ company_id: string
54
+ /**
55
+ * The name of the company.
56
+ */
57
+ name: string
58
+ /**
59
+ * The time the company was created in your system.
60
+ */
61
+ created_at?: string | number
62
+ /**
63
+ * The name of the plan you have associated with the company.
64
+ */
65
+ plan?: string
66
+ /**
67
+ * The monthly spend of the company, e.g. how much revenue the company generates for your business.
68
+ */
69
+ monthly_spend?: number
70
+ /**
71
+ * The number of employees in the company.
72
+ */
73
+ size?: number
74
+ /**
75
+ * The URL for the company website.
76
+ */
77
+ website?: string
78
+ /**
79
+ * The industry that the company operates in.
80
+ */
81
+ industry?: string
82
+ /**
83
+ * The custom attributes for the company object.
84
+ */
85
+ company_custom_traits?: {
86
+ [k: string]: unknown
87
+ }
88
+ }
89
+ /**
90
+ * The array of companies the user is associated to.
91
+ */
92
+ companies?: {
93
+ /**
94
+ * The unique identifier of the company.
95
+ */
96
+ company_id: string
97
+ /**
98
+ * The name of the company.
99
+ */
100
+ name: string
101
+ /**
102
+ * The time the company was created in your system.
103
+ */
104
+ created_at?: string | number
105
+ /**
106
+ * The name of the plan you have associated with the company.
107
+ */
108
+ plan?: string
109
+ /**
110
+ * The monthly spend of the company, e.g. how much revenue the company generates for your business.
111
+ */
112
+ monthly_spend?: number
113
+ /**
114
+ * The number of employees in the company.
115
+ */
116
+ size?: number
117
+ /**
118
+ * The URL for the company website.
119
+ */
120
+ website?: string
121
+ /**
122
+ * The industry that the company operates in.
123
+ */
124
+ industry?: string
125
+ /**
126
+ * The custom attributes for the company object.
127
+ */
128
+ company_custom_traits?: {
129
+ [k: string]: unknown
130
+ }
131
+ }[]
132
+ /**
133
+ * Selectively show the chat widget. As per [Intercom docs](https://www.intercom.com/help/en/articles/189-turn-off-show-or-hide-the-intercom-messenger), you want to first hide the Messenger for all users inside the Intercom UI using Messenger settings. Then think about how you want to programmatically decide which users you would like to show the widget to.
134
+ */
135
+ hide_default_launcher?: boolean
136
+ }