@internetarchive/ia-book-actions 0.1.11-a1 → 0.1.11-b2

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
@@ -88,7 +88,6 @@
88
88
 
89
89
  <body>
90
90
  <ia-book-actions></ia-book-actions>
91
- <modal-manager></modal-manager>
92
91
 
93
92
  <script type="module">
94
93
  /* eslint-disable */
@@ -98,7 +97,6 @@
98
97
  defaultLendingStatus,
99
98
  canBrowseAndBorrow,
100
99
  } from '../src/assets/data/lending-get-status-service.js';
101
- import '@internetarchive/modal-manager';
102
100
  import { ModalConfig } from '@internetarchive/modal-manager';
103
101
  import { LocalCache } from '@internetarchive/local-cache';
104
102
 
@@ -292,7 +290,7 @@
292
290
 
293
291
  document.querySelector('.pageChangedEvent').addEventListener('click', () => {
294
292
  // dispatch event to say book page has flipped
295
- window.dispatchEvent(
293
+ document.querySelector('ia-book-actions').dispatchEvent(
296
294
  new CustomEvent('BookReader:userAction', {
297
295
  detail: {},
298
296
  bubbles: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/ia-book-actions",
3
- "version": "0.1.11-a1",
3
+ "version": "0.1.11-b2",
4
4
  "description": "Bookreader actions for borrowable book",
5
5
  "author": "Internet Archive",
6
6
  "license": "AGPL-3.0-only",
@@ -1,12 +1,9 @@
1
1
  import { html, css, LitElement } from 'lit';
2
- import { sentryLogs } from '../core/config/sentry-events.js';
3
2
 
4
3
  export default class TimerCountdown extends LitElement {
5
4
  static get properties() {
6
5
  return {
7
6
  secondsLeftOnLoan: { type: Number }, // in seconds
8
- loanTotalTime: { type: Number }, // in seconds
9
- loanRenewAtLast: { type: Number }, // in seconds
10
7
  };
11
8
  }
12
9
 
@@ -18,155 +15,6 @@ export default class TimerCountdown extends LitElement {
18
15
  * @type {number}
19
16
  */
20
17
  this.secondsLeftOnLoan = 0;
21
-
22
- /**
23
- * total seconds a loan does have
24
- * @type {number}
25
- */
26
- this.loanTotalTime = 0;
27
-
28
- /**
29
- * at the remaining time, we attempt to renew current loan
30
- * @type {number}
31
- */
32
- this.loanRenewAtLast = 0;
33
-
34
- /**
35
- * store time when timer is started
36
- * @type {string}
37
- */
38
- this.timeWhenTimerStart = '';
39
-
40
- /**
41
- * delay seconds in setInterval function
42
- * @type {number}
43
- */
44
- this.timerExecutionSeconds = 30;
45
- }
46
-
47
- connectedCallback() {
48
- super.connectedCallback();
49
- console.log('connectedCallback - timerCountdown');
50
- }
51
-
52
- disconnectedCallback() {
53
- console.log('disconnectedCallback - timerCountdown IN', window.IALendingIntervals);
54
- window?.IALendingIntervals?.clearTimerCountdown();
55
- console.log('disconnectedCallback - timerCountdown cleared', window.IALendingIntervals);
56
- }
57
-
58
- updated(changed) {
59
- if (changed.has('secondsLeftOnLoan') && this.secondsLeftOnLoan > 0) {
60
- this.timerCountdown();
61
- }
62
- }
63
-
64
- async timerInterval() {
65
- let secondsLeft = this.secondsLeftOnLoan;
66
-
67
- secondsLeft -= this.timerExecutionSeconds;
68
- secondsLeft = Math.round(secondsLeft); // round number
69
-
70
- // re-sync timer if gone off because of background window
71
-
72
- // do we need a window.focus anywhere?
73
- await this.reSyncTimerIfGoneOff(secondsLeft);
74
-
75
- /**
76
- * execute from last 10th minute to 0th minute // arbitrary?
77
- * - 10th - to check if user has viewed
78
- * - till 0th - to show warning msg with remaining time to auto expired
79
- * @see IABookActions::bindLoanRenewEvents
80
- */
81
- if (secondsLeft <= this.loanRenewAtLast) {
82
- this.dispatchLoanRenewEvent(secondsLeft);
83
- }
84
-
85
- // clear interval in secondsLeft if less
86
- if (secondsLeft <= this.timerExecutionSeconds) {
87
- this.disconnectedCallback();
88
- window?.Sentry?.captureMessage(sentryLogs.clearOneHourTimer);
89
- }
90
- }
91
-
92
- timerCountdown() {
93
- console.log('TIMER COUNTDOWN', window.IALendingIntervals, this.timerExecutionSeconds );
94
- this.disconnectedCallback();
95
-
96
-
97
-
98
- // store current time
99
- this.timeWhenTimerStart = new Date();
100
-
101
- // this.dispatchLoanRenewEvent(secondsLeft);
102
- /**
103
- * set interval in window object
104
- * @see ia-lending-intervals.js
105
- */
106
- window.IALendingIntervals.timerCountdown = setInterval(
107
- () => this.timerInterval(),
108
- this.timerExecutionSeconds * 1000
109
- );
110
- }
111
-
112
- /**
113
- * dispatch loan renew attempt event
114
- *
115
- * @param {number} secondsLeft
116
- * @memberof TimerCountdown
117
- */
118
- dispatchLoanRenewEvent(secondsLeft) {
119
- this.dispatchEvent(
120
- new CustomEvent('IABookActions:loanRenew', {
121
- detail: {
122
- hasPageChanged: false,
123
- secondsLeft,
124
- },
125
- bubbles: true,
126
- composed: true,
127
- })
128
- );
129
- }
130
-
131
- /**
132
- * helper function to determine if timer is not in sync properly
133
- *
134
- * @param {number} timerSecondsLeft - actual seconds left get from setInterval
135
- *
136
- * @memberof TimerCountdown
137
- */
138
- async reSyncTimerIfGoneOff(timerSecondsLeft) {
139
- // debug info
140
- console.log(
141
- new Date().toLocaleTimeString(),
142
- 'timeLeftInSec',
143
- timerSecondsLeft,
144
- ' ||| timeLeftInMin',
145
- Math.ceil(timerSecondsLeft / 60)
146
- );
147
-
148
- const currentTime = new Date();
149
-
150
- // current time - loan time
151
- const diffInSeconds =
152
- currentTime.getTime() / 1000 - this.timeWhenTimerStart.getTime() / 1000;
153
-
154
- const secondsShouldLeft = this.secondsLeftOnLoan - diffInSeconds;
155
-
156
- // convert in minutes
157
- const whatIsleft = Math.round(timerSecondsLeft);
158
- const whatShouldLeft = Math.round(secondsShouldLeft);
159
-
160
- if (whatIsleft !== whatShouldLeft) {
161
- // debug info
162
- console.log(
163
- `timer is gone off, let's re-sync, whatIsleft -> ${whatIsleft}, whatShouldLeft -> ${whatShouldLeft}`
164
- );
165
- this.secondsLeftOnLoan = secondsShouldLeft; // the seconds should left in timer again
166
- }
167
-
168
- // when do we resync timer?
169
- // return true or false?
170
18
  }
171
19
 
172
20
  /**
@@ -188,7 +36,6 @@ export default class TimerCountdown extends LitElement {
188
36
  }
189
37
 
190
38
  render() {
191
- console.log("TIMER COUNTDOWN RENDER");
192
39
  return html`
193
40
  <svg
194
41
  width="14"
@@ -196,7 +43,7 @@ export default class TimerCountdown extends LitElement {
196
43
  viewBox="0 0 100 100"
197
44
  xmlns="http://www.w3.org/2000/svg"
198
45
  >
199
- <circle id="timer-countdown" class="circle" cx="50" cy="50" r="50" />
46
+ <circle class="circle" cx="50" cy="50" r="50" />
200
47
  </svg>
201
48
  <span class="sr-only">${this.remainingTime} left</span>
202
49
  `;
@@ -41,13 +41,7 @@ window.IALendingIntervals = {
41
41
  * clear all intervals being used acros lending system
42
42
  */
43
43
  clearAll: () => {
44
- try {
45
-
46
- window.clearInterval(window?.IALendingIntervals.tokenPoller);
47
- window.clearInterval(window?.IALendingIntervals.timerCountdown);
48
- } catch(e) {
49
- console.error(e);
50
- }
51
-
44
+ window.clearInterval(window?.IALendingIntervals?.tokenPoller);
45
+ window.clearInterval(window?.IALendingIntervals?.timerCountdown);
52
46
  },
53
47
  };
@@ -142,6 +142,7 @@ export default class ActionsHandler extends LitElement {
142
142
  action,
143
143
  identifier: this.identifier,
144
144
  success: data => {
145
+ console.log("RENEW_LOAN --- ", data, action, data.loan, this.identifier);
145
146
  if (data?.success === true && data?.loan?.renewal === true) {
146
147
  this.setBrowseTimeSession();
147
148
  this.dispatchEvent(
@@ -164,7 +165,7 @@ export default class ActionsHandler extends LitElement {
164
165
  /**
165
166
  * excute function when loan is returning
166
167
  *
167
- * @param {'returnNow' | ''} type
168
+ * @param {string} type - loan return type returnNow|''
168
169
  */
169
170
  handleReturnIt(type = '') {
170
171
  const action = 'return_loan';
@@ -26,14 +26,11 @@ export class LoanRenewHelper {
26
26
  }
27
27
 
28
28
  handleLoanRenew() {
29
- console.log('handleLoanRenew', this.hasPageChanged);
30
29
  try {
31
30
  if (this.hasPageChanged) {
32
- this.pageChanged(); // user clicked on page
33
- return;
31
+ return this.pageChanged(); // user clicked on page
34
32
  }
35
- this.autoChecker(); // auto checker at last 10th minute
36
- return;
33
+ return this.autoChecker(); // auto checker at last 10th minute
37
34
  } catch (error) {
38
35
  console.log(error);
39
36
  }
@@ -57,16 +54,13 @@ export class LoanRenewHelper {
57
54
 
58
55
  const lastTimeFrame = this.changeTime(loanTime, loanRenewAtLast, 'sub');
59
56
 
60
- console.log("PAGE CHANGED ~~~~~~~~~ lastTimeFram, loanTime", { lastTimeFrame, loanTime });
61
-
62
57
  // if user viewed new page in last 10 minutes, renew immediately
63
58
  if (lastTimeFrame !== null && currentTime >= lastTimeFrame) {
64
59
  this.result.texts = this.loanRenewMessage;
65
60
  this.result.renewNow = true;
66
61
  }
67
- console.log("PAGE CHANGED ~~~~~~~~~ ", this.result);
68
- debugger;
69
- await this.setPageChangedTime();
62
+
63
+ this.setPageChangedTime();
70
64
  return this.result;
71
65
  }
72
66
 
@@ -77,7 +71,6 @@ debugger;
77
71
  * @returns {this.result}
78
72
  */
79
73
  async autoChecker() {
80
- console.log('autoChecker ***!!!!!');
81
74
  const { pageChangedInLast } = this.loanRenewTimeConfig;
82
75
  const pageChangedTime = await this.localCache.get(
83
76
  `${this.identifier}-pageChangedTime`
@@ -45,7 +45,6 @@ export default class IABookActions extends LitElement {
45
45
  userid: { type: String },
46
46
  identifier: { type: String },
47
47
  bookTitle: { type: String },
48
- /** */
49
48
  lendingStatus: { type: Object },
50
49
  returnUrl: { type: String },
51
50
  width: { type: Number },
@@ -78,7 +77,7 @@ export default class IABookActions extends LitElement {
78
77
  this.barType = 'action'; // 'title'|'action'
79
78
  this.sharedObserver = undefined;
80
79
  this.disableActionGroup = false;
81
- // this.modal = undefined;
80
+ this.modal = undefined;
82
81
  this.tokenDelay = 120; // in seconds
83
82
 
84
83
  // private props
@@ -87,15 +86,12 @@ export default class IABookActions extends LitElement {
87
86
  this.primaryColor = 'primary';
88
87
  this.secondaryActions = [];
89
88
  this.lendingOptions = {};
90
- this.borrowType = ''; // (browsed|borrowed)
89
+ this.borrowType = null; // (browsed|borrowed)
91
90
  this.browseTimer = undefined;
91
+ this.timerExecutionSeconds = 30;
92
92
 
93
93
  /** @deprecated */
94
94
  this.toast = undefined;
95
- /** @deprecated */
96
- this.suppressToast = false;
97
- /** @deprecated */
98
- this.suppressAutoRenew = false;
99
95
 
100
96
  /**
101
97
  * when user click on [return the book] button on warning modal
@@ -129,11 +125,6 @@ export default class IABookActions extends LitElement {
129
125
  this._shadowRoot = this.attachShadow({ mode: 'open' });
130
126
  }
131
127
 
132
- connectedCallback() {
133
- super.connectedCallback();
134
- console.log('connectedCallback - ia-book-actions');
135
- }
136
-
137
128
  disconnectedCallback() {
138
129
  // clear all intervals for lending system
139
130
  window?.IALendingIntervals?.clearAll();
@@ -143,28 +134,21 @@ export default class IABookActions extends LitElement {
143
134
  }
144
135
 
145
136
  firstUpdated() {
146
- // window.focus => reset timer & also1w3w
147
- window.addEventListener('focus', () => {
148
- console.log('window focus ~~~~~~');
149
- });
150
-
151
137
  // bind auto loan renew events
152
138
  this.bindLoanRenewEvents();
153
139
 
154
140
  // localCache used for auto-loan-renew
155
141
  this.localCache = new LocalCache({
156
- namespace: `loanRenew-${this.identifier || 'unknown_book'}`,
142
+ namespace: 'loanRenew',
157
143
  });
158
144
 
159
- this.sharedObserver = new SharedResizeObserver();
160
- this.setupResizeObserver();
161
-
162
- const modal = this.modal;
163
- console.log('modal', modal);
145
+ if (!this.sharedObserver) {
146
+ this.sharedObserver = new SharedResizeObserver();
147
+ this.setupResizeObserver();
148
+ }
164
149
  }
165
150
 
166
151
  updated(changed) {
167
- console.log('UPDATED', this.lendingStatus);
168
152
  if (changed.has('lendingStatus') || changed.has('bwbPurchaseUrl')) {
169
153
  this.setupLendingToolbarActions();
170
154
  this.update();
@@ -176,19 +160,6 @@ export default class IABookActions extends LitElement {
176
160
  }
177
161
  }
178
162
 
179
- render() {
180
- console.log("RENDER IABookActions", this.barType);
181
- if (this.barType === 'title') {
182
- return html`<section class="lending-wrapper">
183
- ${this.bookTitleBar}
184
- </section>`;
185
- }
186
-
187
- return html`<section class="lending-wrapper">
188
- ${this.bookActionBar}
189
- </section>`;
190
- }
191
-
192
163
  /** SharedObserver resize handler */
193
164
  handleResize(entry) {
194
165
  // if you are observing multiple targets,
@@ -204,8 +175,7 @@ export default class IABookActions extends LitElement {
204
175
 
205
176
  /** Removes observer */
206
177
  disconnectResizeObserver() {
207
- if (!this.sharedObserver) return;
208
- this.sharedObserver.removeObserver({
178
+ this.sharedObserver?.removeObserver({
209
179
  handler: this,
210
180
  target: this.shadowRoot.host,
211
181
  });
@@ -216,18 +186,13 @@ export default class IABookActions extends LitElement {
216
186
  setupResizeObserver() {
217
187
  if (!this.shadowRoot) return;
218
188
  this.sharedObserver?.addObserver({
219
- handler: {
220
- handleResize: this.handleResize.bind(this),
221
- },
189
+ handler: this,
222
190
  target: this.shadowRoot.host,
223
191
  });
224
192
  }
225
193
  /** End SharedObserver resize handler */
226
194
 
227
195
  async setupLendingToolbarActions() {
228
- this.suppressToast = false;
229
- this.suppressAutoRenew = false;
230
-
231
196
  this.lendingOptions = new GetLendingActions(
232
197
  this.userid,
233
198
  this.identifier,
@@ -247,7 +212,7 @@ export default class IABookActions extends LitElement {
247
212
  return action != null;
248
213
  });
249
214
 
250
- this.borrowType = actions.borrowType;
215
+ this.borrowType = actions.borrowType ? actions.borrowType : null;
251
216
 
252
217
  const hasExpired =
253
218
  'browsingExpired' in this.lendingStatus &&
@@ -272,7 +237,9 @@ export default class IABookActions extends LitElement {
272
237
  }
273
238
 
274
239
  if (this.borrowType === 'browsed') {
275
- console.log('this.borrowType', this.borrowType);
240
+ // start timer for loan-renew
241
+ await this.startTimerCountdown();
242
+
276
243
  // start timer for browsed.
277
244
  await this.startBrowseTimer();
278
245
  }
@@ -288,7 +255,6 @@ export default class IABookActions extends LitElement {
288
255
  setTimeout(() => {
289
256
  this.resetTimerCountState();
290
257
  }, 100);
291
- return;
292
258
  }
293
259
 
294
260
  /**
@@ -311,49 +277,10 @@ export default class IABookActions extends LitElement {
311
277
  * dispatched this event from bookreader page changed
312
278
  */
313
279
  window.addEventListener('BookReader:userAction', () => {
314
- console.log('BookReader:userAction **** , ', this.borrowType);
315
280
  if (this.borrowType === 'browsed') {
316
281
  this.autoLoanRenewChecker(true);
317
282
  }
318
283
  });
319
-
320
- /**
321
- * this event dispatched from timer-countdown component for:
322
- * 1. user turned book page after showing auto-returned warning modal
323
- * 2. show warning modal having remaining time
324
- * @see TimerCountdown::timerCountdown
325
- */
326
- this.addEventListener('IABookActions:loanRenew', async event => {
327
- await this.autoLoanRenewChecker(false);
328
-
329
- /**
330
- * auto-renew is not possible in last seconds (let say 50 second) because,
331
- * 1. less time to execute ajax call
332
- * 2. less time to write loan on datanodes
333
- * 3. less time to load images by create_token api
334
- * so if seconds left is < 50, just expire the loan
335
- */
336
- let secondsLeft = event?.detail?.secondsLeft;
337
- if (secondsLeft < 50) {
338
- this.suppressAutoRenew = true;
339
- console.log("BROWSER TIMER IN secondsLeft < 50!!",secondsLeft, secondsLeft < 50);
340
- console.log("BROWSER TIMER IN secondsLeft < 50!! this.loanRenewResult",this.loanRenewResult);
341
-
342
- this.browseHasExpired();
343
- }
344
-
345
- // show warning modal with remaining time to auto returned it.
346
- if (this.loanRenewResult.renewNow === false) {
347
- /**
348
- * so compensate for the 50 second buffer to handle above race conditions
349
- * let's reduce 1 min from warning texts and early return the book when 1 min left.
350
- */
351
- secondsLeft -= 60;
352
- this.loanRenewResult.secondsLeft = secondsLeft;
353
-
354
- this.showWarningModal();
355
- }
356
- });
357
284
  }
358
285
 
359
286
  /**
@@ -363,17 +290,12 @@ export default class IABookActions extends LitElement {
363
290
  * @param {Boolean} hasPageChanged
364
291
  */
365
292
  async autoLoanRenewChecker(hasPageChanged = false) {
366
- console.log('autoLoanRenewChecker &&&&', this.loanRenewHelper);
367
- // something is up here
368
- if (!this.loanRenewHelper) {
369
- this.loanRenewHelper = new LoanRenewHelper(
370
- hasPageChanged,
371
- this.identifier,
372
- this.localCache,
373
- this.loanRenewTimeConfig
374
- );
375
- }
376
-
293
+ this.loanRenewHelper = new LoanRenewHelper(
294
+ hasPageChanged,
295
+ this.identifier,
296
+ this.localCache,
297
+ this.loanRenewTimeConfig
298
+ );
377
299
 
378
300
  await this.loanRenewHelper.handleLoanRenew();
379
301
  this.loanRenewResult = this.loanRenewHelper.result;
@@ -383,27 +305,23 @@ export default class IABookActions extends LitElement {
383
305
  * create / select the modal-manager component on DOM
384
306
  * @memberof IABookActions
385
307
  */
386
- // async useModalManager() {
387
- // if (!this.modal) {
388
- // this.modal = document.querySelector('modal-manager');
308
+ async useModalManager() {
309
+ if (!this.modal) {
310
+ this.modal = document.querySelector('modal-manager');
389
311
 
390
- // if (!this.modal) this.modal = document.createElement('modal-manager');
391
- // }
312
+ if (!this.modal) this.modal = document.createElement('modal-manager');
313
+ }
392
314
 
393
- // this.modal.id = 'action-bar-modal';
394
- // await document.body.appendChild(this.modal);
395
- // }
315
+ this.modal.id = 'action-bar-modal';
316
+ await document.body.appendChild(this.modal);
317
+ }
396
318
 
397
319
  /**
398
320
  * Show the waring modal to ask user if they are still reading
399
321
  */
400
322
  async showWarningModal() {
401
- console.log('****** showWarningModal ****** clearing intervals');
402
- // await this.useModalManager();
403
- console.log('showWarningModal window?.IALendingInterval BEFORE', window?.IALendingIntervals);
404
-
405
- window?.IALendingIntervals?.clearAll();
406
- console.log('showWarningModal window?.IALendingIntervals AFTER', window?.IALendingIntervals);
323
+ console.log('****** showWarningModal ******');
324
+ await this.useModalManager();
407
325
 
408
326
  // if secondsLeft < 60, consider it 1 minute
409
327
  let { secondsLeft } = this.loanRenewResult;
@@ -426,9 +344,9 @@ export default class IABookActions extends LitElement {
426
344
  <div id="custom-buttons" style="display:flex;justify-content:center;">
427
345
  <button
428
346
  style="${modalButtonStyle.iaButton} ${modalButtonStyle.renew}"
429
- @click=${event => {
430
- this.changeModalState(event);
431
- this.autoLoanRenewChecker(true);
347
+ @click=${async event => {
348
+ await this.changeModalState(event);
349
+ this.loanRenewResult = { texts: '', renewNow: true };
432
350
  }}
433
351
  >
434
352
  Keep reading
@@ -445,7 +363,7 @@ export default class IABookActions extends LitElement {
445
363
  </button>
446
364
  </div> `;
447
365
 
448
- this.modal.showModal({ config, customModalContent: customContent });
366
+ this.modal?.showModal({ config, customModalContent: customContent });
449
367
  }
450
368
 
451
369
  /**
@@ -473,7 +391,8 @@ export default class IABookActions extends LitElement {
473
391
  * Show modal when book is auto returned
474
392
  */
475
393
  async showExpiredModal() {
476
- // await this.useModalManager();
394
+ console.log('showExpiredModal()');
395
+ await this.useModalManager();
477
396
 
478
397
  const config = new ModalConfig();
479
398
  config.headline = '';
@@ -537,12 +456,6 @@ export default class IABookActions extends LitElement {
537
456
  * - show message having remaining time when book is about to auto returned
538
457
  */
539
458
  async showToastMessage() {
540
- console.log('** showToastMessage', {
541
- suppressToast: this.suppressToast,
542
- loanRenewResult: this.loanRenewResult,
543
- });
544
- if (this.suppressToast) return;
545
-
546
459
  await this.useToastManager();
547
460
 
548
461
  // if secondsLeft < 60, consider it 1 minute
@@ -566,7 +479,6 @@ export default class IABookActions extends LitElement {
566
479
  }
567
480
 
568
481
  async browseHasRenew() {
569
- console.log('****** browseHasRenew ******');
570
482
  window?.IALendingIntervals?.clearAll();
571
483
 
572
484
  const loanTime = await this.localCache.get(`${this.identifier}-loanTime`);
@@ -585,7 +497,6 @@ export default class IABookActions extends LitElement {
585
497
  * Execute when loan is expired
586
498
  */
587
499
  async browseHasExpired() {
588
- console.log('browseHasExpired', window?.IALendingIntervals);
589
500
  window?.IALendingIntervals?.clearAll();
590
501
 
591
502
  const currStatus = { ...this.lendingStatus, browsingExpired: true };
@@ -600,13 +511,14 @@ export default class IABookActions extends LitElement {
600
511
  this.loanRenewResult.texts =
601
512
  'This book has been returned due to inactivity.';
602
513
 
603
- this.showExpiredModal();
514
+ await this.showExpiredModal();
604
515
 
605
516
  window?.Sentry?.captureMessage(sentryLogs.browseHasExpired);
606
517
  }
607
518
 
608
519
  async startBrowseTimer() {
609
520
  clearTimeout(this.browseTimer);
521
+ console.log('startBrowseTimerstartBrowseTimer just cleared timer', this.browseTimer, this.lendingStatus);
610
522
 
611
523
  const {
612
524
  browsingExpired,
@@ -618,10 +530,8 @@ export default class IABookActions extends LitElement {
618
530
  return;
619
531
  }
620
532
 
621
- console.log('user browsed', this.lendingStatus);
622
-
623
533
  this.browseTimer = setTimeout(() => {
624
- console.log("BROWSER TIMER IN TIMEOUT!!");
534
+ console.log('start `this.browseTimer will fire his.browseHasExpired() - secondsLeftOnLoan', secondsLeftOnLoan);
625
535
  this.browseHasExpired();
626
536
  }, secondsLeftOnLoan * 1000);
627
537
  }
@@ -637,6 +547,8 @@ export default class IABookActions extends LitElement {
637
547
  const strokeDashOffset =
638
548
  (secondsLeft / this.loanRenewTimeConfig.loanTotalTime) * 315;
639
549
 
550
+ console.log('resetTimerCountState === ', secondsLeft);
551
+
640
552
  // set seconds left in loan expire
641
553
  timerCountdown.style?.setProperty('--secondsLeftOnLoan', `${secondsLeft}s`);
642
554
 
@@ -653,19 +565,16 @@ export default class IABookActions extends LitElement {
653
565
  }, 100);
654
566
  }
655
567
 
656
- get modal () {
657
- let modal = document.querySelector('modal-manager');
658
- if (!modal) {
659
- const newModal = document.createElement('modal-manager');
660
- document.body.appendChild(newModal);
661
- modal = newModal;
662
- }
663
-
664
- if (modal && !modal.id !== 'action-bar-modal') {
665
- modal.setAttribute('id', 'action-bar-modal');
568
+ render() {
569
+ if (this.barType === 'title') {
570
+ return html`<section class="lending-wrapper">
571
+ ${this.bookTitleBar}
572
+ </section>`;
666
573
  }
667
574
 
668
- return modal;
575
+ return html`<section class="lending-wrapper">
576
+ ${this.bookActionBar}
577
+ </section>`;
669
578
  }
670
579
 
671
580
  get bookTitleBar() {
@@ -676,18 +585,14 @@ export default class IABookActions extends LitElement {
676
585
  }
677
586
 
678
587
  get timerCountdownTemplate() {
679
- console.log('timerCountdownTemplatetimerCountdownTemplate');
680
588
  return this.borrowType === 'browsed'
681
589
  ? html`<timer-countdown
682
590
  .secondsLeftOnLoan=${Number(this.lendingStatus.secondsLeftOnLoan)}
683
- .loanTotalTime=${this.loanRenewTimeConfig.loanTotalTime}
684
- .loanRenewAtLast=${this.loanRenewTimeConfig.loanRenewAtLast}
685
591
  ></timer-countdown>`
686
592
  : nothing;
687
593
  }
688
594
 
689
595
  get bookActionBar() {
690
- console.log('~~~~~');
691
596
  return html`
692
597
  <collapsible-action-group
693
598
  .userid=${this.userid}
@@ -733,7 +638,14 @@ export default class IABookActions extends LitElement {
733
638
  secondsLeftOnLoan: Math.round(this.lendingStatus.secondsLeftOnLoan),
734
639
  });
735
640
 
641
+ /**
642
+ * update the lendingStatus property
643
+ */
736
644
  await this.browseHasRenew();
645
+
646
+ /**
647
+ * reset timer countdown states
648
+ */
737
649
  await this.resetTimerCountState();
738
650
 
739
651
  // close the modal
@@ -744,6 +656,138 @@ export default class IABookActions extends LitElement {
744
656
  }
745
657
  }
746
658
 
659
+ /**
660
+ * start timer countdown interval after loan auto-renewed
661
+ *
662
+ * @memberof IABookActions
663
+ */
664
+ startTimerCountdown() {
665
+ console.log('startTimerCountdown()');
666
+ window?.IALendingIntervals?.clearTimerCountdown();
667
+
668
+ let secondsLeft = Number(this.lendingStatus.secondsLeftOnLoan);
669
+ this.timeWhenTimerStart = new Date();
670
+
671
+ window.IALendingIntervals.timerCountdown = setInterval(async () => {
672
+ secondsLeft -= this.timerExecutionSeconds;
673
+ secondsLeft = Math.round(secondsLeft); // round number
674
+
675
+ // re-sync timer if gone off because of background window
676
+ const resync = await this.reSyncTimerIfGoneOff(secondsLeft);
677
+
678
+ console.log("*** startTimerCountdown ***", secondsLeft, resync);
679
+
680
+ if (resync) {
681
+ console.log('have resyncd, will end startTimerCountdown here - ');
682
+ return;
683
+ }
684
+
685
+ console.log('startTimerCountdown - NO RESYNC');
686
+
687
+ /**
688
+ * execute from last 10th minute to 0th minute
689
+ * - 10th - to check if user has viewed
690
+ * - till 0th - to show warning msg with remaining time to auto expired
691
+ * @see IABookActions::bindLoanRenewEvents
692
+ */
693
+ if (secondsLeft <= this.loanRenewTimeConfig.loanRenewAtLast) {
694
+ await this.loanRenewAttempt(secondsLeft);
695
+ }
696
+
697
+ // clear interval in secondsLeft if less
698
+ if (secondsLeft <= this.timerExecutionSeconds) {
699
+ this.disconnectedCallback();
700
+ window?.Sentry?.captureMessage(sentryLogs.clearOneHourTimer);
701
+ }
702
+ }, this.timerExecutionSeconds * 1000);
703
+ }
704
+
705
+ /**
706
+ * helper function to determine if timer is not in sync properly
707
+ *
708
+ * @param {number} timerSecondsLeft - actual seconds left get from setInterval
709
+ *
710
+ * @memberof TimerCountdown
711
+ */
712
+ async reSyncTimerIfGoneOff(timerSecondsLeft) {
713
+ // debug info
714
+ console.log(
715
+ new Date().toLocaleTimeString(),
716
+ 'timeLeftInSec',
717
+ timerSecondsLeft,
718
+ ' ||| timeLeftInMin',
719
+ Math.ceil(timerSecondsLeft / 60)
720
+ );
721
+
722
+ const currentTime = new Date();
723
+
724
+ // current time - loan time
725
+ const diffInSeconds =
726
+ currentTime.getTime() / 1000 - this.timeWhenTimerStart.getTime() / 1000;
727
+
728
+ const secondsShouldLeft =
729
+ this.lendingStatus.secondsLeftOnLoan - diffInSeconds;
730
+
731
+ // convert in minutes
732
+ const whatIsleft = Math.round(timerSecondsLeft);
733
+ const whatShouldLeft = Math.round(secondsShouldLeft);
734
+
735
+ if (whatIsleft !== whatShouldLeft) {
736
+ // debug info
737
+ console.log(
738
+ `timer is gone off, let's re-sync, whatIsleft -> ${whatIsleft}, whatShouldLeft -> ${whatShouldLeft}`
739
+ );
740
+
741
+ // the seconds should left in timer again
742
+ const currStatus = {
743
+ ...this.lendingStatus,
744
+ secondsLeftOnLoan: secondsShouldLeft,
745
+ };
746
+ this.lendingStatus = currStatus;
747
+ return true;
748
+ }
749
+ return false;
750
+ }
751
+
752
+ /**
753
+ * attmept to loan renew from
754
+ * - timer countdown
755
+ * - onclick on [keep reading] button
756
+ *
757
+ * @param {*} secondsLeft
758
+ * @memberof IABookActions
759
+ */
760
+ async loanRenewAttempt(secondsLeft) {
761
+ console.log('loanRenewAttempt()', secondsLeft, this.loanRenewResult);
762
+ let loanSecondsLeft = secondsLeft;
763
+ /**
764
+ * auto-renew is not possible in last seconds (let say 50 second) because,
765
+ * 1. less time to execute ajax call
766
+ * 2. less time to write loan on datanodes
767
+ * 3. less time to load images by create_token api
768
+ * so if seconds left is < 50, just expire the loan
769
+ */
770
+ if (loanSecondsLeft < 50) {
771
+ console.log('if (loanSecondsLeft < 50) {');
772
+ await this.browseHasExpired();
773
+ return;
774
+ }
775
+
776
+ await this.autoLoanRenewChecker(false);
777
+
778
+ // show warning modal with remaining time to auto returned it.
779
+ if (this.loanRenewResult.renewNow === false) {
780
+ /**
781
+ * so compensate for the 50 second buffer to handle above race conditions
782
+ * let's reduce 1 min from warning texts and early return the book when 1 min left.
783
+ */
784
+ loanSecondsLeft -= 60;
785
+ this.loanRenewResult.secondsLeft = loanSecondsLeft;
786
+
787
+ this.showWarningModal();
788
+ }
789
+ }
790
+
747
791
  /**
748
792
  * enable access of borrowed/browsed books
749
793
  * @see LoanTokenPoller
@@ -839,7 +883,7 @@ export default class IABookActions extends LitElement {
839
883
 
840
884
  /* show error message if something went wrong */
841
885
  async showErrorModal(errorMsg, action) {
842
- // await this.useModalManager();
886
+ await this.useModalManager();
843
887
 
844
888
  const modalConfig = new ModalConfig({
845
889
  title: 'Lending error',
@@ -867,7 +911,7 @@ export default class IABookActions extends LitElement {
867
911
  <code>errorLog: ${errorMsg}</code>`;
868
912
  }
869
913
 
870
- this.modal.showModal({
914
+ this.modal?.showModal({
871
915
  config: modalConfig,
872
916
  });
873
917
  }
@@ -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>
File without changes