@internetarchive/ia-book-actions 0.0.29-alpha37 → 0.0.29-alpha38

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
@@ -133,8 +133,8 @@
133
133
 
134
134
  let isDevBox = true;
135
135
  iaBookActions.loanRenewConfig = {
136
- totalTime: isDevBox ? 13 : 3600, // 60 second = 1 min
137
- autoCheckAt: isDevBox ? 10 : 3540, // at last 10th minute
136
+ totalTime: isDevBox ? 10 : 3600, // 60 second = 1 min
137
+ autoCheckAt: isDevBox ? 5 : 3540, // at last 10th minute
138
138
  pageChangedInLast: isDevBox ? 5 : 900, // within last 15 second/minute
139
139
  isDevBox: isDevBox,
140
140
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/ia-book-actions",
3
- "version": "0.0.29-alpha37",
3
+ "version": "0.0.29-alpha38",
4
4
  "description": "Bookreader actions for borrowable book",
5
5
  "author": "Internet Archive",
6
6
  "license": "AGPL-3.0-only",
@@ -72,15 +72,22 @@ export default class IABookActions extends LitElement {
72
72
  this.borrowType = ''; // (browsed|borrowed)
73
73
  this.consecutiveLoanCounts = 1; // consecutive loan count
74
74
 
75
- // loan auto renew
76
- this.browserTimer = undefined;
75
+ /**
76
+ * contains loan renew time config
77
+ * - totalTime:- number of seconds a loan should last
78
+ * - autoCheckAt:- check for loan renew at last
79
+ * - pageChangedInLast: consider loan renew eligible in last
80
+ * - isDevBox:- it just for testing purpose
81
+ */
77
82
  this.loanRenewConfig = {};
78
83
  this.suppressToast = false;
84
+ this.browseTimer = undefined;
79
85
 
80
86
  /**
81
87
  * contains loan auto-renew response
82
88
  * - texts:- texts messages need to show in toast message
83
89
  * - renewNow:- key to determine if need to renew now
90
+ * - timeLeft:- number of seconds left in active loan
84
91
  */
85
92
  this.loanRenewResult = {
86
93
  texts: null,
@@ -92,7 +99,7 @@ export default class IABookActions extends LitElement {
92
99
  }
93
100
 
94
101
  disconnectedCallback() {
95
- this.tokenPoller.disconnectedInterval();
102
+ this.tokenPoller?.disconnectedInterval();
96
103
  window?.Sentry?.captureMessage(sentryLogs.disconnectedCallback);
97
104
  this.disconnectResizeObserver();
98
105
  }
@@ -252,17 +259,17 @@ export default class IABookActions extends LitElement {
252
259
  /**
253
260
  * Detech click-event on document to close toast-template
254
261
  */
255
- document.addEventListener('click', () => {
262
+ document.addEventListener('click', e => {
256
263
  if (this.loanRenewHelper && this.loanRenewResult.timeLeft > 0) {
257
264
  console.log('clicked-outside');
258
265
  this.suppressToast = true;
259
266
  }
260
267
 
261
- // reload when user click on page after it EXPIRED
268
+ // reload when user click on book-page and book is EXPIRED
262
269
  const hasExpired =
263
270
  'browsingExpired' in this.lendingStatus &&
264
271
  this.lendingStatus?.browsingExpired;
265
- if (hasExpired) {
272
+ if (hasExpired && e.target.nodeName !== 'IA-BOOK-ACTIONS') {
266
273
  window.location?.reload();
267
274
  }
268
275
  });
@@ -283,6 +290,11 @@ export default class IABookActions extends LitElement {
283
290
  });
284
291
  }
285
292
 
293
+ /**
294
+ * To determine if need to be renewed browsed book
295
+ *
296
+ * @param {Boolean} hasPageChanged
297
+ */
286
298
  async autoLoanRenewChecker(hasPageChanged = false) {
287
299
  this.loanRenewHelper = new LoanRenewHelper(
288
300
  hasPageChanged,
@@ -304,7 +316,9 @@ export default class IABookActions extends LitElement {
304
316
  async showToastMessage() {
305
317
  if (this.suppressToast) return;
306
318
 
307
- const iaBookActions = document.querySelector('ia-book-actions').shadowRoot;
319
+ const iaBookActions = document.querySelector('ia-book-actions')?.shadowRoot;
320
+ if (!iaBookActions) return;
321
+
308
322
  let toastTemplate = iaBookActions.querySelector('toast-template');
309
323
  if (!toastTemplate) {
310
324
  toastTemplate = document.createElement('toast-template');
@@ -338,8 +352,7 @@ export default class IABookActions extends LitElement {
338
352
  }
339
353
 
340
354
  startBrowseTimer() {
341
- clearTimeout(this.browserTimer);
342
-
355
+ clearTimeout(this.browseTimer);
343
356
  const {
344
357
  browsingExpired,
345
358
  user_has_browsed,
@@ -349,7 +362,7 @@ export default class IABookActions extends LitElement {
349
362
  return;
350
363
  }
351
364
 
352
- this.browserTimer = setTimeout(() => {
365
+ this.browseTimer = setTimeout(() => {
353
366
  this.browseHasExpired();
354
367
  }, secondsLeftOnLoan * 1000);
355
368
  }
@@ -358,11 +371,11 @@ export default class IABookActions extends LitElement {
358
371
  * Execute when loan is expired
359
372
  */
360
373
  async browseHasExpired() {
361
- clearTimeout(this.browserTimer);
362
-
363
374
  const currStatus = { ...this.lendingStatus, browsingExpired: true };
364
375
  this.lendingStatus = currStatus;
365
376
 
377
+ this.tokenPoller?.disconnectedInterval();
378
+
366
379
  // remove respected key:value for loan-renew
367
380
  await this.localCache.delete(`${this.identifier}-loanTime`);
368
381
  await this.localCache.delete(`${this.identifier}-pageChangedTime`);
@@ -468,7 +481,7 @@ export default class IABookActions extends LitElement {
468
481
  */
469
482
  async handleLoanAutoRenewed() {
470
483
  if (this.loanRenewResult.renewNow) {
471
- this.tokenPoller.disconnectedInterval();
484
+ this.tokenPoller?.disconnectedInterval();
472
485
 
473
486
  this.suppressToast = false;
474
487
  await this.showToastMessage();
@@ -491,7 +504,7 @@ export default class IABookActions extends LitElement {
491
504
  startLoanTokenPoller() {
492
505
  if (this.tokenPoller) {
493
506
  window?.Sentry?.captureMessage(sentryLogs.clearTokenPoller);
494
- this.tokenPoller.disconnectedInterval();
507
+ this.tokenPoller?.disconnectedInterval();
495
508
  }
496
509
  const successCallback = () => {
497
510
  this.lendingBarPostInit();
@@ -551,7 +564,7 @@ export default class IABookActions extends LitElement {
551
564
  // - clear tokenPoller interval
552
565
  // - set user_has_browsed to `false`
553
566
  if (action === 'create_token') {
554
- this.tokenPoller.disconnectedInterval();
567
+ this.tokenPoller?.disconnectedInterval();
555
568
 
556
569
  const currStatus = {
557
570
  ...this.lendingStatus,
@@ -230,9 +230,14 @@ describe('Browsing expired status', () => {
230
230
  },
231
231
  })
232
232
  );
233
- expect(el.primaryTitle).contains('Borrow ends at ');
233
+ expect(el.primaryTitle).contains('');
234
234
  expect(el.primaryActions[0].text).to.equal('Return now');
235
235
  expect(el.primaryActions[1].text).to.equal('Print Disability Access');
236
+
237
+ // default params of one-hour loan renew
238
+ expect(el.loanRenewResult.texts).to.equal(null);
239
+ expect(el.loanRenewResult.renewNow).to.equal(false);
240
+ expect(el.loanRenewResult.timeLeft).to.equal(0);
236
241
  });
237
242
 
238
243
  it('Book is browsing and going to expire after 1 second', async () => {
@@ -248,10 +253,63 @@ describe('Browsing expired status', () => {
248
253
  })
249
254
  );
250
255
 
256
+ // timer-countdown is still active
257
+ expect(el.shadowRoot.querySelector('timer-countdown')).to.not.be.null;
258
+
251
259
  await aTimeout(1500); // wait for 1.5 second
252
260
  await el.updateComplete;
253
261
 
254
262
  expect(el.primaryActions[0].text).to.equal('Borrow');
263
+
264
+ // timer-countdown is gone now
265
+ expect(el.shadowRoot.querySelector('timer-countdown')).to.be.null;
266
+
267
+ // book has been expired
268
+ expect(el.loanRenewResult.timeLeft).to.equal(0);
269
+ expect(el.loanRenewResult.texts).to.equal(
270
+ 'This book has been automatically returned due to inactivity.'
271
+ );
272
+ });
273
+
274
+ it('Book is browsing and eligible to renew it', async () => {
275
+ const el = await fixture(
276
+ container({
277
+ userid: '@userid',
278
+ lendingStatus: {
279
+ is_lendable: true,
280
+ user_has_browsed: true,
281
+ browseHasExpired: false,
282
+ secondsLeftOnLoan: 1,
283
+ },
284
+ })
285
+ );
286
+
287
+ // timer-countdown is still active
288
+ // expect(el.shadowRoot.querySelector('timer-countdown')).to.not.be.null
289
+
290
+ // let eventReceived = false;
291
+ // const listener = () => {
292
+ // eventReceived = true;
293
+ // };
294
+ // el.addEventListener('IABookReader:userAction', listener);
295
+
296
+ el.loanRenewResult = {
297
+ texts: 'book has been renewed',
298
+ renewNow: true,
299
+ timeLeft: 10,
300
+ };
301
+
302
+ await aTimeout(1500); // wait for 1.5 second
303
+ await el.updateComplete;
304
+
305
+ // // timer-countdown is gone now
306
+ // expect(el.shadowRoot.querySelector('timer-countdown')).to.not.be.null
307
+ // expect(el.shadowRoot.querySelector('toast-template')).to.not.be.null
308
+
309
+ expect(el.loanRenewResult.timeLeft).to.equal(10);
310
+ // // book has been expired
311
+ // expect(el.loanRenewResult.timeLeft).to.equal(0);
312
+ // expect(el.loanRenewResult.texts).to.equal('This book has been automatically returned due to inactivity.');
255
313
  });
256
314
 
257
315
  it('Expiring book cancels interval & emits event', async () => {
@@ -276,9 +334,8 @@ describe('Browsing expired status', () => {
276
334
  el.lendingStatus = browsingStatus;
277
335
  await el.updateComplete;
278
336
 
279
- expect(el.primaryTitle).contains('Borrow ends at ');
337
+ expect(el.primaryTitle).contains('');
280
338
  expect(el.primaryActions[0].text).to.equal('Return now');
281
- expect(el.tokenPoller.loanTokenInterval).to.not.equal(undefined);
282
339
 
283
340
  const expiredStatus = { ...browsingStatus, browsingExpired: true };
284
341
  el.lendingStatus = expiredStatus;
@@ -327,3 +384,40 @@ describe('Shared Resize Observer', () => {
327
384
  expect(component.sharedObserver).to.not.be.undefined;
328
385
  });
329
386
  });
387
+
388
+ describe('Shared Resize Observer', () => {
389
+ it('can receive a Shared Resize Observer', async () => {
390
+ const sharedObserverStub = new SharedResizeObserver();
391
+ const addObserverSpy = Sinon.spy(sharedObserverStub, 'addObserver');
392
+ const component = await fixture(html` <ia-book-actions
393
+ .userid=${'@userid'}
394
+ .identifier=${'foo'}
395
+ .lendingStatus=${{
396
+ is_lendable: true,
397
+ user_has_browsed: true,
398
+ available_to_browse: true,
399
+ available_to_borrow: true,
400
+ }}
401
+ .sharedObserver=${sharedObserverStub}
402
+ ></ia-book-actions>`);
403
+ await component.updateComplete;
404
+
405
+ expect(addObserverSpy.callCount).to.equal(1);
406
+ });
407
+
408
+ it('loads its own resize observer if it is not received', async () => {
409
+ const component = await fixture(html` <ia-book-actions
410
+ .userid=${'@userid'}
411
+ .identifier=${'foo'}
412
+ .lendingStatus=${{
413
+ is_lendable: true,
414
+ user_has_browsed: true,
415
+ available_to_browse: true,
416
+ available_to_borrow: true,
417
+ }}
418
+ ></ia-book-actions>`);
419
+
420
+ await component.updateComplete;
421
+ expect(component.sharedObserver).to.not.be.undefined;
422
+ });
423
+ });