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