@internetarchive/ia-book-actions 0.1.5-alpha1 → 0.1.5-alpha2

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.
package/demo/index.html CHANGED
@@ -128,7 +128,7 @@
128
128
  iaBookActions.modalConfig = modalConfig;
129
129
  iaBookActions.lendingBarPostInit = lendingBarPostInit;
130
130
  iaBookActions.tokenDelay = 2; // 2 seconds
131
- iaBookActions.returnUrl = 'https://openlibrary.org';
131
+ iaBookActions.returnUrl = '';
132
132
  iaBookActions.localCache = localCache;
133
133
 
134
134
  let loanTotalTime2Min = { loanTotalTime: 10, loanRenewAtLast: 5, pageChangedInLast: 5 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/ia-book-actions",
3
- "version": "0.1.5-alpha1",
3
+ "version": "0.1.5-alpha2",
4
4
  "description": "Bookreader actions for borrowable book",
5
5
  "author": "Internet Archive",
6
6
  "license": "AGPL-3.0-only",
@@ -1,18 +1,16 @@
1
1
  import { LitElement } from 'lit';
2
2
 
3
3
  import { URLHelper } from '../../config/url-helper.js';
4
- import { sentryLogs } from '../../config/sentry-events.js';
5
- import { analyticsCategories } from '../../config/analytics-event-and-category.js';
6
4
 
7
5
  import ActionsHandlerService from './actions-handler-service.js';
6
+ import LoanAnanlytics from '../loan-analytics.js';
8
7
  import * as Cookies from '../doc-cookies.js';
9
8
 
10
9
  /**
11
10
  * These are callback functions calling from actions-config.js file.
12
11
  *
13
- * ActionsHandlerService is a function being used to execute
14
- * APIs based of the request made by user. It consist some parameters are as follows:-
15
- * 1. identifier: book name.
12
+ * ActionsHandlerService is a function being used to execute APIs based of the request made by user.
13
+ *
16
14
  */
17
15
 
18
16
  export default class ActionsHandler extends LitElement {
@@ -25,200 +23,149 @@ export default class ActionsHandler extends LitElement {
25
23
  */
26
24
  this.waitUntillBorrowComplete = 6; // in seconds
27
25
 
28
- this.bindEvents();
29
- }
30
-
31
- /**
32
- * reponsible to sent events to GA
33
- *
34
- * @param {string} eventCategory
35
- * @param {string} eventAction
36
- * @memberof ActionsHandler
37
- */
38
- sendEvent(eventCategory, eventAction, label, extraParams) {
39
- window?.archive_analytics?.send_event_no_sampling(
40
- eventCategory,
41
- eventAction,
42
- label || `identifier=${this.identifier}`,
43
- extraParams
44
- );
45
- }
26
+ /**
27
+ * bind events for lending bar
28
+ * @type {object}
29
+ */
30
+ this.loanAnanlytics = new LoanAnanlytics();
46
31
 
47
- get getLoanCountStorageKey() {
48
- return `br-browse-${this.identifier}`;
32
+ /**
33
+ * bind events for lending bar
34
+ * @type {Function}
35
+ */
36
+ this.bindEvents();
49
37
  }
50
38
 
51
39
  bindEvents() {
52
40
  this.addEventListener('browseBook', ({ detail }) => {
53
41
  this.handleBrowseIt();
54
- this.setConsecutiveLoanCounts('browseBook');
42
+ this.loanAnanlytics?.storeLoanStatsCount(this.identifier, 'browse');
55
43
  const { category, action } = detail.event;
56
- this.sendEvent(category, action);
44
+ this.loanAnanlytics?.sendEvent(
45
+ category,
46
+ action,
47
+ `identifier=${this.identifier}`
48
+ );
57
49
  });
58
50
 
59
51
  this.addEventListener('browseBookAgain', ({ detail }) => {
60
52
  this.handleBrowseIt();
61
- this.setConsecutiveLoanCounts('browseBookAgain');
53
+ this.loanAnanlytics?.storeLoanStatsCount(this.identifier, 'browseagain');
62
54
  const { category, action } = detail.event;
63
- this.sendEvent(category, action);
55
+ this.loanAnanlytics?.sendEvent(
56
+ category,
57
+ action,
58
+ `identifier=${this.identifier}`
59
+ );
64
60
  });
65
61
 
66
62
  this.addEventListener('autoRenew', ({ detail }) => {
67
63
  this.handleLoanRenewNow();
68
- this.setConsecutiveLoanCounts('autoRenew');
64
+ this.loanAnanlytics?.storeLoanStatsCount(this.identifier, 'autorenew');
69
65
  const { category, action } = detail.event;
70
- this.sendEvent(category, action);
66
+ this.loanAnanlytics?.sendEvent(
67
+ category,
68
+ action,
69
+ `identifier=${this.identifier}`
70
+ );
71
71
  });
72
72
 
73
73
  this.addEventListener('autoReturn', ({ detail }) => {
74
- this.setConsecutiveLoanCounts('autoReturn');
74
+ this.loanAnanlytics?.storeLoanStatsCount(this.identifier, 'autoreturn');
75
75
  const { category, action } = detail.event;
76
- this.sendEvent(category, action);
76
+ this.loanAnanlytics?.sendEvent(
77
+ category,
78
+ action,
79
+ `identifier=${this.identifier}`
80
+ );
77
81
  });
78
82
 
79
83
  this.addEventListener('returnNow', ({ detail }) => {
84
+ this.loanAnanlytics?.storeLoanStatsCount(this.identifier, 'return');
80
85
  this.handleReturnIt();
81
86
  const { category, action } = detail.event;
82
- this.sendEvent(category, action);
87
+ this.loanAnanlytics?.sendEvent(
88
+ category,
89
+ action,
90
+ `identifier=${this.identifier}`
91
+ );
83
92
  });
84
93
 
85
94
  this.addEventListener('borrowBook', ({ detail }) => {
86
95
  this.handleBorrowIt();
87
96
  const { category, action } = detail.event;
88
- this.sendEvent(category, action);
97
+ this.loanAnanlytics?.sendEvent(
98
+ category,
99
+ action,
100
+ `identifier=${this.identifier}`
101
+ );
89
102
  });
90
103
 
91
104
  this.addEventListener('loginAndBorrow', ({ detail }) => {
92
105
  this.handleLoginOk();
93
106
  const { category, action } = detail.event;
94
- this.sendEvent(category, action);
107
+ this.loanAnanlytics?.sendEvent(
108
+ category,
109
+ action,
110
+ `identifier=${this.identifier}`
111
+ );
95
112
  });
96
113
 
97
114
  this.addEventListener('leaveWaitlist', ({ detail }) => {
98
115
  this.handleRemoveFromWaitingList();
99
116
  const { category, action } = detail.event;
100
- this.sendEvent(category, action);
117
+ this.loanAnanlytics?.sendEvent(
118
+ category,
119
+ action,
120
+ `identifier=${this.identifier}`
121
+ );
101
122
  });
102
123
 
103
124
  this.addEventListener('joinWaitlist', ({ detail }) => {
104
125
  this.handleReserveIt();
105
126
  const { category, action } = detail.event;
106
- this.sendEvent(category, action);
127
+ this.loanAnanlytics?.sendEvent(
128
+ category,
129
+ action,
130
+ `identifier=${this.identifier}`
131
+ );
107
132
  });
108
133
 
109
134
  this.addEventListener('purchaseBook', ({ detail }) => {
110
135
  const { category, action } = detail.event;
111
- this.sendEvent(category, action);
136
+ this.loanAnanlytics?.sendEvent(
137
+ category,
138
+ action,
139
+ `identifier=${this.identifier}`
140
+ );
112
141
  });
113
142
 
114
143
  this.addEventListener('adminAccess', ({ detail }) => {
115
144
  const { category, action } = detail.event;
116
- this.sendEvent(category, action);
145
+ this.loanAnanlytics?.sendEvent(
146
+ category,
147
+ action,
148
+ `identifier=${this.identifier}`
149
+ );
117
150
  });
118
151
 
119
152
  this.addEventListener('exitAdminAccess', ({ detail }) => {
120
153
  const { category, action } = detail.event;
121
- this.sendEvent(category, action);
154
+ this.loanAnanlytics?.sendEvent(
155
+ category,
156
+ action,
157
+ `identifier=${this.identifier}`
158
+ );
122
159
  });
123
160
 
124
161
  this.addEventListener('bookTitleBar', ({ detail }) => {
125
162
  const { category, action } = detail.event;
126
- this.sendEvent(category, action);
127
- });
128
- }
129
-
130
- /**
131
- * store consecutive one hour loan counts in cookies for GA
132
- *
133
- * There are two possible way of consecutive loan
134
- * - book is browsed again just after getting expired
135
- * - book loan is auto renewed for another hour
136
- *
137
- * @param {string} action - user action on book
138
- * @return {void}
139
- * @memberof ActionsHandler
140
- */
141
- async setConsecutiveLoanCounts(action = '') {
142
- try {
143
- await this.getConsecutiveLoanRecord(action);
144
-
145
- const date = new Date();
146
- date.setHours(date.getHours() + 2); // 2 hours
147
-
148
- // set new value
149
- Cookies.setItem(
150
- this.getLoanCountStorageKey,
151
- JSON.stringify(this.lendingEventCounts),
152
- date,
153
- '/'
154
- );
155
- } catch (error) {
156
- console.log(error);
157
- window?.Sentry?.captureException(
158
- `${sentryLogs.setConsecutiveLoanCounts} - Error: ${error}`
163
+ this.loanAnanlytics?.sendEvent(
164
+ category,
165
+ action,
166
+ `identifier=${this.identifier}`
159
167
  );
160
- this.sendEvent('Cookies-Error-Actions', error);
161
- }
162
- }
163
-
164
- /**
165
- * Get consecutive loan count records from cookies for GA
166
- *
167
- * @param {string} action
168
- * @memberof ActionsHandler
169
- */
170
- async getConsecutiveLoanRecord(action) {
171
- const gaStats = { browse: 0, renew: 0, expire: 0 };
172
-
173
- this.lendingEventCounts = JSON.parse(
174
- Cookies.getItem(this.getLoanCountStorageKey)
175
- );
176
-
177
- let browse = this.lendingEventCounts?.browse ?? 0;
178
- let renew = this.lendingEventCounts?.renew ?? 0;
179
- let expire = this.lendingEventCounts?.expire ?? 0;
180
-
181
- if (this.lendingEventCounts !== null) {
182
- switch (action) {
183
- case 'browseBook' || 'browseBookAgain':
184
- browse = browse ? Number(browse) + 1 : 1;
185
- gaStats.browse = browse;
186
- break;
187
-
188
- case 'autoRenew':
189
- renew = renew ? Number(renew) + 1 : 1;
190
- gaStats.renew = renew;
191
- this.sendEvent(
192
- analyticsCategories.browse,
193
- `BookAutoRenewedFor${renew}`
194
- );
195
- break;
196
-
197
- case 'autoReturn':
198
- expire = expire ? Number(expire) + 1 : 1;
199
- gaStats.expire = expire;
200
-
201
- renew = 0; // reset renew count when book is expired
202
- break;
203
- default:
204
- break;
205
- }
206
- }
207
-
208
- // store these counts in cookies
209
- this.lendingEventCounts = { browse, renew, expire };
210
-
211
- // send google analytics events
212
- this.sendEvent(
213
- analyticsCategories.browse,
214
- `browse${gaStats.browse}-autoRenew${gaStats.renew}-autoExpire${gaStats.expire}`,
215
- '',
216
- {
217
- browse: gaStats.browse,
218
- renew: gaStats.renew,
219
- expire: gaStats.expire,
220
- }
221
- );
168
+ });
222
169
  }
223
170
 
224
171
  handleBrowseIt() {
@@ -334,7 +281,7 @@ export default class ActionsHandler extends LitElement {
334
281
  */
335
282
  dispatchActionError(action, data = {}) {
336
283
  // send LendingServiceError to GA
337
- this.sendEvent('LendingServiceError', action);
284
+ this.loanAnanlytics?.sendEvent('LendingServiceError', action);
338
285
 
339
286
  this.dispatchEvent(
340
287
  new CustomEvent('lendingActionError', {
@@ -0,0 +1,189 @@
1
+ /* eslint-disable class-methods-use-this */
2
+
3
+ import { analyticsCategories } from '../config/analytics-event-and-category.js';
4
+ import * as Cookies from './doc-cookies.js';
5
+
6
+ /**
7
+ * This class is used to send different GA events for loan system.
8
+ */
9
+ export default class LoanAnanlytics {
10
+ constructor() {
11
+ this.identifier = undefined;
12
+
13
+ /**
14
+ * contains the counts we send to GA
15
+ * @type {object}
16
+ * - @param {number} - browse count
17
+ * - @param {number} - renew count
18
+ * - @param {number} - expire count
19
+ */
20
+ this.gaStats = {};
21
+ }
22
+
23
+ /**
24
+ * store loan stats count in cookies to remember the count we need to sent GA
25
+ *
26
+ * @param {string} identifier - book id
27
+ * @param {string} action - user action on book
28
+ * @return {void}
29
+ * @memberof ActionsHandler
30
+ */
31
+ async storeLoanStatsCount(idetifier, action = '') {
32
+ this.identifier = idetifier;
33
+
34
+ try {
35
+ await this.getLoanStatsCount(action);
36
+
37
+ const date = new Date();
38
+ date.setHours(date.getHours() + 2); // 2 hours
39
+
40
+ // set new value
41
+ Cookies.setItem(
42
+ this.getLoanCountStorageKey,
43
+ JSON.stringify(this.lendingEventCounts),
44
+ date,
45
+ '/'
46
+ );
47
+ } catch (error) {
48
+ console.log(error);
49
+ this.sendEvent(
50
+ 'Cookies-Error-Actions',
51
+ error,
52
+ `identifier=${this.identifier}`
53
+ );
54
+ }
55
+ }
56
+
57
+ /**
58
+ * get loan stats count from cookies for GA
59
+ *
60
+ * @param {string} action 'browse'|'autorenew'|etc...
61
+ * @memberof ActionsHandler
62
+ */
63
+ async getLoanStatsCount(action) {
64
+ this.lendingEventCounts = JSON.parse(
65
+ Cookies.getItem(this.getLoanCountStorageKey)
66
+ );
67
+
68
+ this.gaStats = this.lendingEventCounts ?? {
69
+ browse: 0,
70
+ renew: 0,
71
+ expire: 0,
72
+ };
73
+
74
+ let { browse, renew, expire } = this.lendingEventCounts ?? 0;
75
+
76
+ switch (action) {
77
+ case 'browse' || 'browseagain':
78
+ browse = browse ? Number(browse) + 1 : 1;
79
+ this.gaStats.browse = browse;
80
+
81
+ // reset renew and expire count when browse
82
+ renew = 0;
83
+ expire = 0;
84
+ break;
85
+
86
+ case 'autorenew':
87
+ renew = renew ? Number(renew) + 1 : 1;
88
+ this.gaStats.renew = renew;
89
+ break;
90
+
91
+ case 'return' || 'autoreturn':
92
+ expire = expire ? Number(expire) + 1 : 1;
93
+ this.gaStats.expire = expire;
94
+
95
+ // reset renew and expire count when browse
96
+ renew = 0;
97
+ expire = 0;
98
+ break;
99
+ default:
100
+ break;
101
+ }
102
+
103
+ // store these counts in cookies
104
+ this.lendingEventCounts = { browse, renew, expire };
105
+
106
+ // obtain GA category, event
107
+ // const { category, event } = await this.getGACategoryAction(action);
108
+ const category = analyticsCategories.browse;
109
+ const event = `browse${this.paddedNumber(
110
+ this.gaStats?.browse
111
+ )}-autorenew${this.paddedNumber(this.gaStats?.renew)}:${action}`;
112
+
113
+ // send google analytics events
114
+ this.sendEvent(category, event, `identifier=${this.identifier}`, {
115
+ browse: this.gaStats?.browse,
116
+ renew: this.gaStats?.renew,
117
+ expire: this.gaStats?.expire,
118
+ });
119
+ }
120
+
121
+ /**
122
+ *
123
+ *
124
+ * @param {string} action - like 'browse|autorenew|etc...'
125
+ * @return {object} - contains GA category and event
126
+ * - @param {string}
127
+ * - @param {string}
128
+ *
129
+ * @memberof LoanAnanlytics
130
+ */
131
+ getGACategoryAction(action) {
132
+ const GACategory = analyticsCategories.browse;
133
+ const GAAction = `browse${this.paddedNumber(
134
+ this.gaStats?.browse
135
+ )}-autorenew${this.paddedNumber(this.gaStats?.renew)}:${action}`;
136
+
137
+ return { GACategory, GAAction };
138
+ }
139
+
140
+ /**
141
+ * get zero padded number
142
+ *
143
+ * @param {number} number
144
+ * @return {string} browse001|autorenew001
145
+ * @memberof LoanAnanlytics
146
+ */
147
+ paddedNumber(number) {
148
+ return number.toString().padStart(3, '0');
149
+ }
150
+
151
+ /**
152
+ * get storage key for loan stats count
153
+ *
154
+ * @readonly
155
+ * @memberof LoanAnanlytics
156
+ */
157
+ get getLoanCountStorageKey() {
158
+ return `br-browse-${this.identifier}`;
159
+ }
160
+
161
+ /**
162
+ * reponsible to sent events to GA
163
+ *
164
+ * @param {*} eventCategory
165
+ * @param {*} eventAction
166
+ * @param {*} label
167
+ * @param {*} extraParams
168
+ * @memberof LoanAnanlytics
169
+ */
170
+ sendEvent(eventCategory, eventAction, label, extraParams) {
171
+ console.debug(
172
+ 'eventCategory:- ',
173
+ eventCategory,
174
+ '\neventAction:- ',
175
+ eventAction,
176
+ '\nlabel:- ',
177
+ label,
178
+ '\nextraParams:- ',
179
+ extraParams
180
+ );
181
+
182
+ window?.archive_analytics?.send_event_no_sampling(
183
+ eventCategory,
184
+ eventAction,
185
+ label || `identifier=${this.identifier}`,
186
+ extraParams
187
+ );
188
+ }
189
+ }
@@ -1,4 +1,5 @@
1
1
  import ActionsHandlerService from './actions-handler/actions-handler-service.js';
2
+ import LoanAnanlytics from './loan-analytics.js';
2
3
  import { sentryLogs } from '../config/sentry-events.js';
3
4
 
4
5
  import * as Cookies from './doc-cookies.js';
@@ -17,6 +18,13 @@ export class LoanTokenPoller {
17
18
  this.pollerDelay = pollerDelay; // value in seconds
18
19
 
19
20
  this.loanTokenInterval = undefined;
21
+
22
+ /**
23
+ * loan analytics instance
24
+ * @see loan-analytics.js
25
+ */
26
+ this.loanAnalytics = new LoanAnanlytics();
27
+
20
28
  this.bookAccessed();
21
29
  }
22
30
 
@@ -39,7 +47,6 @@ export class LoanTokenPoller {
39
47
  window?.Sentry?.captureException(
40
48
  `${sentryLogs.enableBookAcces} - CookieError: ${error}`
41
49
  );
42
- this.sendEvent('Cookies-Error-Token', error);
43
50
  }
44
51
  }
45
52
 
@@ -65,7 +72,11 @@ export class LoanTokenPoller {
65
72
  this.borrowType === 'browsed' ? 'BrowseCounts-' : 'Counts-'
66
73
  }${consecutiveLoanCounts}`;
67
74
 
68
- this.sendEvent(category, action);
75
+ this.loanAnalytics?.sendEvent(
76
+ category,
77
+ action,
78
+ `identifier=${this.identifier}`
79
+ );
69
80
  } else {
70
81
  window?.Sentry?.captureMessage(
71
82
  `${sentryLogs.bookAccessed} - not borrowed`
@@ -76,14 +87,6 @@ export class LoanTokenPoller {
76
87
  }
77
88
  }
78
89
 
79
- sendEvent(eventCategory, eventAction) {
80
- window?.archive_analytics?.send_event_no_sampling(
81
- eventCategory,
82
- eventAction,
83
- `identifier=${this.identifier}`
84
- );
85
- }
86
-
87
90
  async handleLoanTokenPoller(isInitial = false) {
88
91
  const action = 'create_token';
89
92
  ActionsHandlerService({
@@ -98,7 +101,11 @@ export class LoanTokenPoller {
98
101
  );
99
102
 
100
103
  // send LendingServiceError to GA
101
- this.sendEvent('LendingServiceLoanError', action);
104
+ this.loanAnalytics?.sendEvent(
105
+ 'LendingServiceLoanError',
106
+ action,
107
+ `identifier=${this.identifier}`
108
+ );
102
109
  },
103
110
  success: () => {
104
111
  if (isInitial) this.successCallback();