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

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
@@ -131,11 +131,11 @@
131
131
  iaBookActions.returnUrl = 'https://openlibrary.org';
132
132
  iaBookActions.localCache = localCache;
133
133
 
134
- let loanTotalTime2Min = { loanTotalTime: 20, loanRenewAtLast: 15, pageChangedInLast: 15 };
135
- let loanTotalTime5Min = { loanTotalTime: 300, loanRenewAtLast: 180, pageChangedInLast: 15 };
134
+ let loanTotalTime2Min = { loanTotalTime: 10, loanRenewAtLast: 5, pageChangedInLast: 5 };
135
+ let loanTotalTime5Min = { loanTotalTime: 300, loanRenewAtLast: 290, pageChangedInLast: 15 };
136
136
  let loanTotalTime1Hour = { loanTotalTime: 3600, loanRenewAtLast: 600, pageChangedInLast: 900 };
137
137
 
138
- iaBookActions.loanRenewTimeConfig = loanTotalTime1Hour;
138
+ iaBookActions.loanRenewTimeConfig = loanTotalTime2Min;
139
139
 
140
140
  let lendingStatus1 = iaBookActions.lendingStatus;
141
141
  let secondsLeftOnLoan = iaBookActions.loanRenewTimeConfig.loanTotalTime;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/ia-book-actions",
3
- "version": "0.1.4",
3
+ "version": "0.1.5-alpha1",
4
4
  "description": "Bookreader actions for borrowable book",
5
5
  "author": "Internet Archive",
6
6
  "license": "AGPL-3.0-only",
@@ -32,7 +32,8 @@ export class CollapsibleActionGroup extends ActionsHandler {
32
32
  dropdownArrow: { type: String },
33
33
  disabled: { type: Boolean },
34
34
  returnUrl: { type: String },
35
- renewNow: { type: Boolean },
35
+ autoRenew: { type: Boolean },
36
+ autoReturn: { type: Boolean },
36
37
  };
37
38
  }
38
39
 
@@ -52,7 +53,8 @@ export class CollapsibleActionGroup extends ActionsHandler {
52
53
  this.loaderIcon = 'https://archive.org/upload/images/tree/loading.gif';
53
54
  this.disabled = false;
54
55
  this.returnUrl = '';
55
- this.renewNow = false;
56
+ this.autoRenew = false;
57
+ this.autoReturn = false;
56
58
  }
57
59
 
58
60
  updated(changed) {
@@ -63,21 +65,33 @@ export class CollapsibleActionGroup extends ActionsHandler {
63
65
  this.resetActions();
64
66
  }
65
67
 
66
- if (changed.has('renewNow') && this.renewNow === true) {
67
- this.dispatchLoanRenewEvent();
68
+ if (changed.has('autoRenew') && this.autoRenew === true) {
69
+ this.dispatchLoanEvent('autoRenew');
70
+ }
71
+
72
+ if (changed.has('autoReturn') && this.autoReturn === true) {
73
+ this.dispatchLoanEvent('autoReturn');
68
74
  }
69
75
  }
70
76
 
71
- // dispatch this event to loan renew handler
72
- dispatchLoanRenewEvent() {
73
- const { category, action } = {
74
- category: analyticsCategories.browse,
75
- action: analyticsActions.browseLoanRenew,
76
- };
77
+ /**
78
+ * dispatch event when book is auto renewed / returned
79
+ * listen these events in action-handler.js
80
+ * @see ActionsHandler
81
+ *
82
+ * @param {string} event - autoRenew|autoReturn
83
+ * @memberof CollapsibleActionGroup
84
+ */
85
+ dispatchLoanEvent(event) {
86
+ const category = analyticsCategories.browse;
87
+ const action =
88
+ event === 'autoRenew'
89
+ ? analyticsActions.browseAutoRenew
90
+ : analyticsActions.browseAutoReturn;
77
91
 
78
92
  // listen in action-handler.js to execute ajax call on petabox.
79
93
  this.dispatchEvent(
80
- new CustomEvent('loanRenew', {
94
+ new CustomEvent(event, {
81
95
  detail: {
82
96
  event: { category, action },
83
97
  },
@@ -31,43 +31,51 @@ export default class TimerCountdown extends LitElement {
31
31
  */
32
32
  this.loanRenewAtLast = 0;
33
33
 
34
+ /**
35
+ * store time when timer is started
36
+ * @type {string}
37
+ */
38
+ this.timeWhenTimerStart = '';
39
+
34
40
  /**
35
41
  * delay seconds in setInterval function
36
42
  * @type {number}
37
43
  */
38
- this.timerExecutionSeconds = 0;
44
+ this.timerExecutionSeconds = 60;
39
45
  }
40
46
 
41
47
  disconnectedCallback() {
42
48
  window?.IALendingIntervals?.clearTimerCountdown();
43
49
  }
44
50
 
51
+ firstUpdated() {
52
+ this.timerCountdown();
53
+ }
54
+
45
55
  updated(changed) {
46
56
  if (changed.has('secondsLeftOnLoan') && this.secondsLeftOnLoan > 0) {
47
- this.disconnectedCallback();
48
-
49
57
  this.timerCountdown();
50
58
  }
51
59
  }
52
60
 
53
61
  timerCountdown() {
54
- // - let just execute setInterval in every 1 minute
55
- this.timerExecutionSeconds = 60;
62
+ this.disconnectedCallback();
63
+
64
+ let secondsLeft = this.secondsLeftOnLoan;
65
+
66
+ // store current time
67
+ this.timeWhenTimerStart = new Date();
56
68
 
57
69
  /**
58
70
  * set interval in window object
59
71
  * @see ia-lending-intervals.js
60
72
  */
61
- window.IALendingIntervals.timerCountdown = setInterval(() => {
62
- this.secondsLeftOnLoan -= this.timerExecutionSeconds;
63
- const secondsLeft = Math.round(this.secondsLeftOnLoan);
73
+ window.IALendingIntervals.timerCountdown = setInterval(async () => {
74
+ secondsLeft -= this.timerExecutionSeconds;
75
+ secondsLeft = Math.round(secondsLeft); // round number
64
76
 
65
- console.log(
66
- 'timeLeftInSec',
67
- secondsLeft,
68
- ' ||| timeLeftInMin',
69
- Math.ceil(secondsLeft / 60)
70
- );
77
+ // re-sync timer is gone off
78
+ await this.reSyncTimerIfGoneOff(secondsLeft);
71
79
 
72
80
  /**
73
81
  * execute from last 10th minute to 0th minute
@@ -76,26 +84,74 @@ export default class TimerCountdown extends LitElement {
76
84
  * @see IABookActions::bindLoanRenewEvents
77
85
  */
78
86
  if (secondsLeft <= this.loanRenewAtLast) {
79
- this.dispatchEvent(
80
- new CustomEvent('IABookActions:loanRenew', {
81
- detail: {
82
- hasPageChanged: false,
83
- secondsLeft,
84
- },
85
- bubbles: true,
86
- composed: true,
87
- })
88
- );
87
+ this.dispatchLoanRenewEvent(secondsLeft);
89
88
  }
90
89
 
91
- // clear interval
92
- if (secondsLeft <= 60) {
90
+ // clear interval in secondsLeft if less
91
+ if (secondsLeft <= this.timerExecutionSeconds) {
93
92
  this.disconnectedCallback();
94
93
  window?.Sentry?.captureMessage(sentryLogs.clearOneHourTimer);
95
94
  }
96
95
  }, this.timerExecutionSeconds * 1000);
97
96
  }
98
97
 
98
+ /**
99
+ * dispatch loan renew attempt event
100
+ *
101
+ * @param {number} secondsLeft
102
+ * @memberof TimerCountdown
103
+ */
104
+ dispatchLoanRenewEvent(secondsLeft) {
105
+ this.dispatchEvent(
106
+ new CustomEvent('IABookActions:loanRenew', {
107
+ detail: {
108
+ hasPageChanged: false,
109
+ secondsLeft,
110
+ },
111
+ bubbles: true,
112
+ composed: true,
113
+ })
114
+ );
115
+ }
116
+
117
+ /**
118
+ * helper function to determine if timer is not in sync properly
119
+ *
120
+ * @param {number} timerSecondsLeft - actual seconds left get from setInterval
121
+ *
122
+ * @memberof TimerCountdown
123
+ */
124
+ async reSyncTimerIfGoneOff(timerSecondsLeft) {
125
+ // debug info
126
+ console.log(
127
+ new Date().toLocaleTimeString(),
128
+ 'timeLeftInSec',
129
+ timerSecondsLeft,
130
+ ' ||| timeLeftInMin',
131
+ Math.ceil(timerSecondsLeft / 60)
132
+ );
133
+
134
+ const currentTime = new Date();
135
+
136
+ // current time - loan time
137
+ const diffInSeconds =
138
+ currentTime.getTime() / 1000 - this.timeWhenTimerStart.getTime() / 1000;
139
+
140
+ const secondsShouldLeft = this.secondsLeftOnLoan - diffInSeconds;
141
+
142
+ // convert in minutes
143
+ const whatIsleft = Math.round(timerSecondsLeft);
144
+ const whatShouldLeft = Math.round(secondsShouldLeft);
145
+
146
+ if (whatIsleft !== whatShouldLeft) {
147
+ // debug info
148
+ console.log(
149
+ `timer is gone off, let's re-sync, whatIsleft -> ${whatIsleft}, whatShouldLeft -> ${whatShouldLeft}`
150
+ );
151
+ this.secondsLeftOnLoan = secondsShouldLeft; // the seconds should left in timer again
152
+ }
153
+ }
154
+
99
155
  /**
100
156
  * get remaining time with timeunit
101
157
  *
@@ -13,7 +13,8 @@ export const analyticsCategories = {
13
13
  export const analyticsActions = {
14
14
  browse: 'Borrow-1Hour',
15
15
  browseAgain: 'Borrow-Again',
16
- browseLoanRenew: 'Borrow-Loan-Renew',
16
+ browseAutoRenew: 'AutoRenewBook',
17
+ browseAutoReturn: 'AutoReturnBook',
17
18
  borrow: 'Borrow-14Days',
18
19
  waitlistJoin: 'JoinWaitlist',
19
20
  waitlistLeave: 'LeaveWaitlist',
@@ -2,6 +2,7 @@ import { LitElement } from 'lit';
2
2
 
3
3
  import { URLHelper } from '../../config/url-helper.js';
4
4
  import { sentryLogs } from '../../config/sentry-events.js';
5
+ import { analyticsCategories } from '../../config/analytics-event-and-category.js';
5
6
 
6
7
  import ActionsHandlerService from './actions-handler-service.js';
7
8
  import * as Cookies from '../doc-cookies.js';
@@ -27,31 +28,50 @@ export default class ActionsHandler extends LitElement {
27
28
  this.bindEvents();
28
29
  }
29
30
 
30
- sendEvent(eventCategory, eventAction) {
31
- window?.archive_analytics?.send_event(
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(
32
40
  eventCategory,
33
41
  eventAction,
34
- `identifier=${this.identifier}`
42
+ label || `identifier=${this.identifier}`,
43
+ extraParams
35
44
  );
36
45
  }
37
46
 
47
+ get getLoanCountStorageKey() {
48
+ return `br-browse-${this.identifier}`;
49
+ }
50
+
38
51
  bindEvents() {
39
52
  this.addEventListener('browseBook', ({ detail }) => {
40
53
  this.handleBrowseIt();
41
- this.setConsecutiveLoanCounts();
54
+ this.setConsecutiveLoanCounts('browseBook');
42
55
  const { category, action } = detail.event;
43
56
  this.sendEvent(category, action);
44
57
  });
45
58
 
46
59
  this.addEventListener('browseBookAgain', ({ detail }) => {
47
60
  this.handleBrowseIt();
48
- this.setConsecutiveLoanCounts('browseAgain');
61
+ this.setConsecutiveLoanCounts('browseBookAgain');
62
+ const { category, action } = detail.event;
63
+ this.sendEvent(category, action);
64
+ });
65
+
66
+ this.addEventListener('autoRenew', ({ detail }) => {
67
+ this.handleLoanRenewNow();
68
+ this.setConsecutiveLoanCounts('autoRenew');
49
69
  const { category, action } = detail.event;
50
70
  this.sendEvent(category, action);
51
71
  });
52
72
 
53
- this.addEventListener('loanRenew', ({ detail }) => {
54
- this.handleLoanRenew();
73
+ this.addEventListener('autoReturn', ({ detail }) => {
74
+ this.setConsecutiveLoanCounts('autoReturn');
55
75
  const { category, action } = detail.event;
56
76
  this.sendEvent(category, action);
57
77
  });
@@ -107,6 +127,100 @@ export default class ActionsHandler extends LitElement {
107
127
  });
108
128
  }
109
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}`
159
+ );
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
+ );
222
+ }
223
+
110
224
  handleBrowseIt() {
111
225
  const action = 'browse_book';
112
226
  this.dispatchToggleActionGroup();
@@ -124,7 +238,7 @@ export default class ActionsHandler extends LitElement {
124
238
  });
125
239
  }
126
240
 
127
- handleLoanRenew() {
241
+ handleLoanRenewNow() {
128
242
  const action = 'renew_loan';
129
243
 
130
244
  ActionsHandlerService({
@@ -271,31 +385,6 @@ export default class ActionsHandler extends LitElement {
271
385
  }, this.waitUntillBorrowComplete * 1000);
272
386
  }
273
387
 
274
- // save consecutive loan count for borrow
275
- async setConsecutiveLoanCounts(action = '') {
276
- try {
277
- let newCount = 1;
278
- const storageKey = `loan-count-${this.identifier}`;
279
- const existingCount = Cookies.getItem(storageKey);
280
-
281
- // increase browse-count by 1 when you consecutive reading a book.
282
- if (action === 'browseAgain' && existingCount !== undefined) {
283
- newCount = existingCount ? Number(existingCount) + 1 : 1;
284
- }
285
-
286
- const date = new Date();
287
- date.setHours(date.getHours() + 2); // 2 hours
288
-
289
- // set new value
290
- Cookies.setItem(storageKey, newCount, date, '/');
291
- } catch (error) {
292
- window?.Sentry?.captureException(
293
- `${sentryLogs.setConsecutiveLoanCounts} - Error: ${error}`
294
- );
295
- this.sendEvent('Cookies-Error-Actions', error);
296
- }
297
- }
298
-
299
388
  /**
300
389
  * set browse time in indexedDB
301
390
  */
@@ -62,7 +62,7 @@ export function setItem(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
62
62
 
63
63
  /**
64
64
  * BROKEN Remove specific key's value from cookie
65
- * @fixme hasItem isn't even implemented! This will always error.
65
+ *
66
66
  * @param {string} sKey cookie name
67
67
  * @param {string} [sPath] path of current item
68
68
  * @param {string} [sDomain]
@@ -81,3 +81,25 @@ export function removeItem(sKey, sPath, sDomain) {
81
81
 
82
82
  return true;
83
83
  }
84
+
85
+ /**
86
+ * determine if a specific cookie is exist
87
+ *
88
+ * @param {string} sKey cookie name
89
+ *
90
+ * @returns {boolean}
91
+ */
92
+ export function hasItem(sKey) {
93
+ const reCNameAllowed = /^(?:expires|max\-age|path|domain|secure|samesite|httponly)$/i;
94
+
95
+ // eslint-disable-next-line
96
+ if (!sKey || reCNameAllowed.test(sKey)) {
97
+ return false;
98
+ }
99
+
100
+ return new RegExp(
101
+ '(?:^|;\\s*)' +
102
+ encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, '\\$&') +
103
+ '\\s*\\='
104
+ ).test(document.cookie);
105
+ }
@@ -77,7 +77,7 @@ export class LoanTokenPoller {
77
77
  }
78
78
 
79
79
  sendEvent(eventCategory, eventAction) {
80
- window?.archive_analytics?.send_event(
80
+ window?.archive_analytics?.send_event_no_sampling(
81
81
  eventCategory,
82
82
  eventAction,
83
83
  `identifier=${this.identifier}`
@@ -11,7 +11,6 @@ import './components/book-title-bar.js';
11
11
  import './components/text-group.js';
12
12
  import './components/info-icon.js';
13
13
  import './components/timer-countdown.js';
14
- import './core/config/ia-lending-intervals.js';
15
14
 
16
15
  import { GetLendingActions } from './core/services/get-lending-actions.js';
17
16
  import { mobileContainerWidth } from './core/config/constants.js';
@@ -19,6 +18,9 @@ import { sentryLogs } from './core/config/sentry-events.js';
19
18
  import { LoanTokenPoller } from './core/services/loan-token-poller.js';
20
19
  import { LoanRenewHelper } from './core/services/loan-renew-helper.js';
21
20
 
21
+ import './core/config/ia-lending-intervals.js';
22
+ import * as Cookies from './core/services/doc-cookies.js';
23
+
22
24
  export const events = {
23
25
  browseExpired: 'IABookReader:BrowsingHasExpired',
24
26
  };
@@ -236,16 +238,10 @@ export default class IABookActions extends LitElement {
236
238
  /**
237
239
  * tokenPoller determines if user has loan token for this book
238
240
  * - if book is going to renew, need to wait until renew is completed
239
- * - otherwise execute immediately
240
241
  */
241
- setTimeout(
242
- () => {
243
- this.startLoanTokenPoller();
244
- },
245
-
246
- // if book is renew while reading, let's wait to execute create-token api
247
- this.loanRenewResult.renewNow ? this.tokenDelay * 1000 : 100
248
- );
242
+ setTimeout(() => {
243
+ if (!hasExpired) this.startLoanTokenPoller();
244
+ }, 100);
249
245
  }
250
246
 
251
247
  /**
@@ -260,12 +256,12 @@ export default class IABookActions extends LitElement {
260
256
  * dispatched this event from bookreader page changed
261
257
  */
262
258
  window.addEventListener('BookReader:userAction', () => {
259
+ this.suppressToast = true;
260
+ this.closeToastManager();
261
+
263
262
  if (this.borrowType === 'browsed') {
264
- this.suppressToast = false;
265
263
  this.autoLoanRenewChecker(true);
266
264
  }
267
-
268
- return nothing;
269
265
  });
270
266
 
271
267
  /**
@@ -320,6 +316,16 @@ export default class IABookActions extends LitElement {
320
316
  this.loanRenewResult = this.loanRenewHelper.result;
321
317
  }
322
318
 
319
+ /**
320
+ * close/hide toast message
321
+ */
322
+ async closeToastManager() {
323
+ const toastTemplate = this.shadowRoot.querySelector('toast-template');
324
+ if (toastTemplate) {
325
+ toastTemplate?.remove();
326
+ }
327
+ }
328
+
323
329
  /**
324
330
  * Show toast messages on some specific loan renew features. e.g.
325
331
  * - show message when book is auto renewed
@@ -329,14 +335,11 @@ export default class IABookActions extends LitElement {
329
335
  async showToastMessage() {
330
336
  if (this.suppressToast) return;
331
337
 
332
- const iaBookActions = document.querySelector('ia-book-actions')?.shadowRoot;
333
- if (!iaBookActions) return;
334
-
335
- let toastTemplate = iaBookActions.querySelector('toast-template');
338
+ let toastTemplate = this.shadowRoot.querySelector('toast-template');
336
339
  if (!toastTemplate) {
337
340
  toastTemplate = document.createElement('toast-template');
338
341
  }
339
- await iaBookActions.appendChild(toastTemplate);
342
+ await this.shadowRoot.appendChild(toastTemplate);
340
343
 
341
344
  // if secondsLeft < 60, consider it 1 minute
342
345
  let { secondsLeft } = this.loanRenewResult;
@@ -402,6 +405,9 @@ export default class IABookActions extends LitElement {
402
405
  await this.localCache.delete(`${this.identifier}-loanTime`);
403
406
  await this.localCache.delete(`${this.identifier}-pageChangedTime`);
404
407
 
408
+ // remove loan-renew-count-<identifier> cookie
409
+ Cookies.removeItem(`loan-renew-count-${this.identifier}`);
410
+
405
411
  // show message after browsed book is expired.
406
412
  this.loanRenewResult.renewNow = false;
407
413
  this.loanRenewResult.texts =
@@ -484,7 +490,8 @@ export default class IABookActions extends LitElement {
484
490
  .loanTotalTime=${this.loanRenewTimeConfig.loanTotalTime}
485
491
  ?hasAdminAccess=${this.hasAdminAccess}
486
492
  ?disabled=${this.disableActionGroup}
487
- ?renewNow=${this.loanRenewResult.renewNow}
493
+ ?autoRenew=${this.loanRenewResult.renewNow}
494
+ ?autoReturn=${this.lendingStatus.browsingExpired}
488
495
  @loanAutoRenewed=${this.handleLoanAutoRenewed}
489
496
  @lendingActionError=${this.handleLendingActionError}
490
497
  @toggleActionGroup=${this.handleToggleActionGroup}
@@ -573,8 +580,7 @@ export default class IABookActions extends LitElement {
573
580
  * @param {string} event.detail.data.error - error message
574
581
  */
575
582
  handleLendingActionError(event) {
576
- // toggle activity loader
577
- this.handleToggleActionGroup();
583
+ this.disableActionGroup = false;
578
584
 
579
585
  // clear all intervals for lending system when error occured
580
586
  window?.IALendingIntervals?.clearAll();
@@ -582,7 +588,9 @@ export default class IABookActions extends LitElement {
582
588
  const action = event?.detail?.action;
583
589
  const errorMsg = event?.detail?.data?.error;
584
590
 
585
- if (errorMsg) this.showErrorModal(errorMsg, action);
591
+ // template not show create_token errors
592
+ if (errorMsg && action !== 'create_token')
593
+ this.showErrorModal(errorMsg, action);
586
594
 
587
595
  // if error related to loan token
588
596
  // - clear tokenPoller interval
@@ -616,8 +624,6 @@ export default class IABookActions extends LitElement {
616
624
 
617
625
  /* show error message if something went wrong */
618
626
  async showErrorModal(errorMsg, action) {
619
- this.disableActionGroup = false;
620
-
621
627
  // check if this.modal passed as prop
622
628
  if (!this.modal) {
623
629
  this.modal = document.querySelector('modal-manager');
@@ -1,146 +0,0 @@
1
- <!doctype html>
2
- <html lang="en-GB">
3
-
4
- <head>
5
- <meta charset="utf-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
7
- <style>
8
- html {
9
- font-size: 10px;
10
- /* This is to match petabox's base font size */
11
- }
12
- body {
13
- margin: 0;
14
- text-align: center;
15
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
16
- }
17
- #demo {
18
- height: 50px;
19
- }
20
- ia-book-actions {
21
- --white: #fff;
22
- --black: #000;
23
- --primaryBGColor: var(--black);
24
- --secondaryBGColor: #222;
25
- --tertiaryBGColor: #333;
26
- --primaryTextColor: var(--white);
27
- --primaryCTAFill: #194880;
28
- --primaryCTABorder: #c5d1df;
29
- --secondaryCTAFill: #333;
30
- --secondaryCTABorder: #999;
31
- --secondaryCTAFillRGB: 51, 51, 51;
32
- --primaryErrorCTAFill: #e51c26;
33
- --primaryErrorCTABorder: #f8c6c8;
34
- --primaryCTAFillRGB: 25, 72, 128;
35
- --primaryErrorCTAFillRGB: 229, 28, 38;
36
- --primaryDisableCTAFill: #767676;
37
- }
38
-
39
- fieldset {
40
- width: fit-content;
41
- margin-top: 50px;
42
- }
43
- fieldset legend {
44
- text-align: left;
45
- font-size: 12px;
46
- }
47
- td {
48
- color: white;
49
- font-size: 14px;
50
- border-radius: 5%;
51
- display: table-cell;
52
- text-align: initial;
53
- margin: 5px 0;
54
- width: max-content;
55
- display: block;
56
- }
57
- label {
58
- padding: 10px;
59
- display: block;
60
- cursor: pointer;
61
- margin: 2px;
62
- background: #4e545a;
63
- border-radius: 10px;
64
- }
65
- input[type="radio"], input[type="checkbox"] {
66
- margin-top: 0;
67
- vertical-align: middle;
68
- }
69
-
70
- .initial td {
71
- float: left;
72
- margin: 2px;
73
- }
74
-
75
- body.modal-manager-open {
76
- overflow: hidden;
77
- }
78
-
79
- modal-manager[mode='closed'] {
80
- display: none;
81
- }
82
- </style>
83
- </head>
84
-
85
- <body>
86
- <ia-bookreader class="focus-on-child-only" signedin="" fullscreen="">
87
- <div slot="header">
88
- <ia-book-actions></ia-book-actions>
89
- </div>
90
- <div slot="main">
91
- <div id="BookReader"></div>
92
- </div>
93
- </ia-bookreader>
94
-
95
-
96
- <script type="module">
97
- /* eslint-disable */
98
- import '@internetarchive/bookreader';
99
- import '@internetarchive/bookreader/BookReader/jquery-1.10.1.js';
100
- import '@internetarchive/bookreader/BookReader/BookReader.js';
101
- import '../src/ia-book-actions.js';
102
- import {
103
- defaultLendingStatus,
104
- canBrowseAndBorrow,
105
- } from '../src/assets/data/lending-get-status-service.js';
106
- import { ModalConfig } from '@internetarchive/modal-manager';
107
-
108
- const userid = '@neeraj-archive';
109
- const identifier = 'naturalhistoryof00unse_4111';
110
- let bwbPurchaseUrl = 'https://www.betterworldbooks.com/product/detail/cambridge-ancient-hist-v04-0521044863';
111
-
112
- let iaBookActions = document.querySelector('ia-book-actions');
113
-
114
- // for debugging
115
- window.iaBookActions = iaBookActions;
116
-
117
- const modalConfig = new ModalConfig();
118
- modalConfig.headerColor = '#d9534f';
119
-
120
- let lendingBarPostInit = function lendingBarPostInit() {
121
- setTimeout(function() {
122
- console.log('executed', 'br.init()');
123
- }, 100);
124
- }
125
-
126
- // set defaultLendingStatus for unavailable (without borrowables) book
127
- iaBookActions.userid = userid;
128
- iaBookActions.identifier = identifier;
129
- iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
130
- iaBookActions.lendingStatus = canBrowseAndBorrow;
131
- iaBookActions.bwbPurchaseUrl = '';
132
- iaBookActions.modalConfig = modalConfig;
133
- iaBookActions.lendingBarPostInit = lendingBarPostInit;
134
- iaBookActions.tokenDelay = 2000; // 2 seconds
135
- iaBookActions.returnUrl = 'https://openlibrary.org';
136
-
137
- let lendingStatus1 = iaBookActions.lendingStatus;
138
-
139
- const manifest = await fetch('https://ia801302.us.archive.org/BookReader/BookReaderJSIA.php?id=goody&itemPath=/29/items/goody&server=ia801302.us.archive.org&format=jsonp&subPrefix=goody&requestUri=/details/goody/mode/1up%3Fview%3Dtheater%26ui%3Dembed%26wrapper%3Dfalse');
140
-
141
- console.log('manifest ****', manifest).then(res => res.json());
142
- </script>
143
-
144
- </div>
145
- </body>
146
- </html>