1
+ 'use strict' ;
2
+
3
+ /**
4
+ * Module dependencies.
5
+ */
6
+
7
+ var Identify = require ( 'segmentio-facade' ) . Identify ;
8
+ var Track = require ( 'segmentio-facade' ) . Track ;
9
+ var integration = require ( '@segment/analytics.js-integration' ) ;
10
+ var normalize = require ( 'to-no-case' ) ;
11
+ var qs = require ( 'component-querystring' ) ;
12
+ var sha256 = require ( 'js-sha256' ) ;
13
+
14
+ /**
15
+ * Expose `Nanigans`.
16
+ */
17
+
18
+ var Nanigans = module . exports = integration ( 'Nanigans' )
19
+ . option ( 'appId' , '' )
20
+ . option ( 'events' , { } )
21
+ . tag ( 'page' , '<img src="//api.nanigans.com/event.php?app_id={{ appId }}&type=visit&name=landing">' )
22
+ . tag ( 'track' , '<img src="//api.nanigans.com/event.php?app_id={{ appId }}&type={{ type }}&name={{ name }}&user_id={{ userId }}&ut1={{ ut1 }}">' )
23
+ . tag ( 'track_no_user_id' , '<img src="//api.nanigans.com/event.php?app_id={{ appId }}&type={{ type }}&name={{ name }}&ut1={{ ut1 }}">' )
24
+ . tag ( 'product' , '<img src="//api.nanigans.com/event.php?app_id={{ appId }}&type=purchase&name={{ name }}&user_id={{ userId }}&ut1={{ ut1 }}&sku={{ sku }}">' )
25
+ . tag ( 'add_to_cart' , '<img src="//api.nanigans.com/event.php?app_id={{ appId }}&type=user&name={{ name }}&user_id={{ userId }}&ut1={{ ut1 }}&{{ products }}">' )
26
+ . tag ( 'add_to_cart_no_user_id' , '<img src="//api.nanigans.com/event.php?app_id={{ appId }}&type=user&name={{ name }}&ut1={{ ut1 }}&{{ products }}">' )
27
+ . tag ( 'purchase' , '<img src="//api.nanigans.com/event.php?app_id={{ appId }}&type={{ type }}&name={{ name }}&user_id={{ userId }}&ut1={{ ut1 }}&unique={{ orderId }}&{{ products }}">' )
28
+ . tag ( 'purchase_no_user_id' , '<img src="//api.nanigans.com/event.php?app_id={{ appId }}&type={{ type }}&name={{ name }}&ut1={{ ut1 }}&unique={{ orderId }}&{{ products }}">' ) ;
29
+
30
+ /**
31
+ * Initialize.
32
+ *
33
+ * https://s3.amazonaws.com/segmentio/docs/integrations/nanigans/docs.html
34
+ *
35
+ * @api public
36
+ */
37
+
38
+ Nanigans . prototype . initialize = function ( ) {
39
+ // TODO: assert nan_pid URL parameter is present.
40
+ this . ready ( ) ;
41
+ } ;
42
+
43
+ /**
44
+ * Loaded?
45
+ *
46
+ * @api public
47
+ * @return {boolean }
48
+ */
49
+
50
+ Nanigans . prototype . loaded = function ( ) {
51
+ // We load Nanigans pixels on conversions, so we don't need to preload anything
52
+ return true ;
53
+ } ;
54
+
55
+ /**
56
+ * Page.
57
+ *
58
+ * @api public
59
+ * @param {Page } page
60
+ */
61
+
62
+ Nanigans . prototype . page = function ( ) {
63
+ this . load ( 'page' ) ;
64
+ } ;
65
+
66
+ /**
67
+ * Track.
68
+ *
69
+ * @api public
70
+ * @param {Track } track
71
+ */
72
+
73
+ Nanigans . prototype . track = function ( track ) {
74
+ var user = this . analytics . user ( ) ;
75
+
76
+ var events = get ( this . options . events , track . event ( ) ) ;
77
+ if ( ! events . length ) return ;
78
+ var products = track . products ( ) ;
79
+ var data = { } ;
80
+
81
+ data . app_id = this . options . appId ;
82
+ data . user_id = user . id ( ) ;
83
+ data . unique = track . orderId ( ) ;
84
+ data . sku = Array ( products . length ) ;
85
+ data . qty = Array ( products . length ) ;
86
+ data . value = Array ( products . length ) ;
87
+
88
+ // see readme comment
89
+ if ( email ( user ) != null ) {
90
+ data . ut1 = sha256 ( email ( user ) ) ;
91
+ }
92
+
93
+ for ( var i = 0 ; i < products . length ; i ++ ) {
94
+ var item = new Track ( { properties : products [ i ] } ) ;
95
+ data . qty [ i ] = item . quantity ( ) ;
96
+ data . sku [ i ] = item . sku ( ) ;
97
+ data . value [ i ] = item . price ( ) ;
98
+ }
99
+
100
+ // some events may create multiple pixels.
101
+ for ( var j = 0 ; j < events . length ; j ++ ) {
102
+ var event = events [ j ] ;
103
+ var params = {
104
+ appId : data . app_id ,
105
+ name : renderByProxy ( event . name , track ) ,
106
+ type : event . type ,
107
+ ut1 : data . ut1 ,
108
+ products : { }
109
+ } ;
110
+ if ( data . user_id ) params . userId = data . user_id ;
111
+
112
+ switch ( event . type ) {
113
+ case 'purchase' :
114
+ params . orderId = data . unique ;
115
+ params . products . qty = data . qty ;
116
+ params . products . value = data . value ;
117
+ params . products . sku = data . sku ;
118
+ params . products = qs . stringify ( params . products ) ;
119
+ params . userId ? this . load ( 'purchase' , params ) : this . load ( 'purchase_no_user_id' , params ) ;
120
+ break ;
121
+ case 'user' :
122
+ switch ( event . name ) {
123
+ case 'product' :
124
+ params . sku = data . sku ;
125
+ break ;
126
+ case 'add_to_cart' :
127
+ params . products . qty = data . qty ;
128
+ params . products . value = data . value ;
129
+ params . products . sku = data . sku ;
130
+ params . products = qs . stringify ( params . products ) ;
131
+ params . userId ? this . load ( 'add_to_cart' , params ) : this . load ( 'add_to_cart_no_user_id' , params ) ;
132
+ break ;
133
+ default :
134
+ params . userId ? this . load ( 'track' , params ) : this . load ( 'track_no_user_id' , params ) ;
135
+ break ;
136
+ }
137
+ break ;
138
+ default :
139
+ params . userId ? this . load ( 'track' , params ) : this . load ( 'track_no_user_id' , params ) ;
140
+ break ;
141
+ }
142
+ }
143
+ } ;
144
+
145
+ /**
146
+ * Get an event of `name`.
147
+ *
148
+ * Given something like this:
149
+ *
150
+ * [
151
+ * { key: 'a', value: { type: 'user', name: 'register' } }
152
+ * { key: 'a', value: { type: 'user', name: 'invite' } }
153
+ * { key: 'b', value: { type: 'purchase', name: 'main' } }
154
+ * ]
155
+ *
156
+ * If you do `get(events, 'a')`, it wll give you:
157
+ *
158
+ * [
159
+ * { type: 'user', name: 'register' },
160
+ * { type: 'user', name: 'invite' }
161
+ * ]
162
+ *
163
+ * @param {Array } events
164
+ * @param {String } name
165
+ * @return {Object }
166
+ */
167
+
168
+ function get ( events , name ) {
169
+ var a = normalize ( name ) ;
170
+ var ret = [ ] ;
171
+
172
+ for ( var i = 0 ; i < events . length ; ++ i ) {
173
+ var b = normalize ( events [ i ] . key || events [ i ] . event ) ;
174
+ if ( b === a ) ret . push ( events [ i ] . value || events [ i ] ) ;
175
+ }
176
+
177
+ return ret ;
178
+ }
179
+
180
+ /**
181
+ * Get email from user.
182
+ *
183
+ * @param {Object } user
184
+ * @return {String }
185
+ */
186
+
187
+ function email ( user ) {
188
+ var identify = new Identify ( { userId : user . id ( ) , traits : user . traits ( ) } ) ;
189
+ return identify . email ( ) ;
190
+ }
191
+
192
+ /**
193
+ * Render Nanigans event name from template.
194
+ *
195
+ * @param {Object } user
196
+ * @return {String }
197
+ */
198
+
199
+ function renderByProxy ( template , facade ) {
200
+ return template . replace ( / \{ \{ \ * ( \w + ?[ \. \w + ] * ?) \ * \} \} / g, function ( _ , $1 ) {
201
+ return facade . proxy ( $1 ) || '' ;
202
+ } ) ;
203
+ }
0 commit comments