@internetarchive/ia-book-actions 0.0.29-alpha4 → 0.0.29-alpha40
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 +41 -33
- package/package.json +13 -5
- package/src/assets/styles/collapsible-action-group.js +2 -1
- package/src/components/collapsible-action-group.js +25 -12
- package/src/components/info-icon.js +0 -9
- package/src/components/text-group.js +1 -1
- package/src/components/timer-countdown.js +85 -75
- package/src/core/config/analytics-event-and-category.js +1 -0
- package/src/core/config/sentry-events.js +20 -0
- package/src/core/services/actions-config.js +2 -2
- package/src/core/services/actions-handler/actions-handler-service.js +5 -2
- package/src/core/services/actions-handler/actions-handler.js +46 -35
- package/src/core/services/get-lending-actions.js +6 -11
- package/src/core/services/loan-renew-helper.js +163 -0
- package/src/core/services/loan-token-poller.js +19 -10
- package/src/ia-book-actions.js +323 -135
- package/test/components/collapsible-action-group.test.js +2 -2
- package/test/components/timer-countdown.test.js +47 -0
- package/test/core/services/get-lending-actions.test.js +4 -4
- package/test/core/services/loan-renew-helper.test.js +87 -0
- package/test/ia-book-actions.test.js +75 -12
- package/src/assets/styles/timer-countdown.js +0 -58
- package/src/components/toast-message.js +0 -76
- package/src/core/services/one-hour-auto-renew.js +0 -152
package/src/ia-book-actions.js
CHANGED
|
@@ -3,6 +3,7 @@ import { html, css, LitElement, nothing } from 'lit';
|
|
|
3
3
|
|
|
4
4
|
import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
|
|
5
5
|
import { ModalConfig } from '@internetarchive/modal-manager';
|
|
6
|
+
import { ToastConfig } from '@internetarchive/toast-manager';
|
|
6
7
|
import { LocalCache } from '@internetarchive/local-cache';
|
|
7
8
|
|
|
8
9
|
import './components/collapsible-action-group.js';
|
|
@@ -10,12 +11,12 @@ import './components/book-title-bar.js';
|
|
|
10
11
|
import './components/text-group.js';
|
|
11
12
|
import './components/info-icon.js';
|
|
12
13
|
import './components/timer-countdown.js';
|
|
13
|
-
import './components/toast-message.js';
|
|
14
14
|
|
|
15
15
|
import { GetLendingActions } from './core/services/get-lending-actions.js';
|
|
16
16
|
import { mobileContainerWidth } from './core/config/constants.js';
|
|
17
|
+
import { sentryLogs } from './core/config/sentry-events.js';
|
|
17
18
|
import { LoanTokenPoller } from './core/services/loan-token-poller.js';
|
|
18
|
-
import {
|
|
19
|
+
import { LoanRenewHelper } from './core/services/loan-renew-helper.js';
|
|
19
20
|
|
|
20
21
|
export const events = {
|
|
21
22
|
browseExpired: 'IABookReader:BrowsingHasExpired',
|
|
@@ -36,17 +37,13 @@ export default class IABookActions extends LitElement {
|
|
|
36
37
|
attribute: false,
|
|
37
38
|
},
|
|
38
39
|
barType: { type: String },
|
|
39
|
-
autoRenew: { type: Boolean },
|
|
40
40
|
sharedObserver: { attribute: false },
|
|
41
41
|
disableActionGroup: { type: Boolean },
|
|
42
42
|
modal: { Object },
|
|
43
43
|
tokenDelay: { type: Number },
|
|
44
|
-
toastTexts: { type: String },
|
|
45
|
-
remainingTime: { type: Number },
|
|
46
|
-
resetTimerCountdown: { type: Boolean },
|
|
47
44
|
localCache: { type: Object },
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
loanRenewTimeConfig: { type: Object },
|
|
46
|
+
loanRenewResult: { type: Object },
|
|
50
47
|
};
|
|
51
48
|
}
|
|
52
49
|
|
|
@@ -61,16 +58,10 @@ export default class IABookActions extends LitElement {
|
|
|
61
58
|
this.bwbPurchaseUrl = '';
|
|
62
59
|
this.lendingBarPostInit = () => {};
|
|
63
60
|
this.barType = 'action'; // 'title'|'action'
|
|
64
|
-
this.autoRenew = false;
|
|
65
61
|
this.sharedObserver = undefined;
|
|
66
62
|
this.disableActionGroup = false;
|
|
67
63
|
this.modal = undefined;
|
|
68
|
-
this.tokenDelay =
|
|
69
|
-
this.localCache = new LocalCache({
|
|
70
|
-
namespace: '1HourLoanStorage'
|
|
71
|
-
}),
|
|
72
|
-
this.autoRenewConfig = {},
|
|
73
|
-
this.autoRenewObj = undefined;
|
|
64
|
+
this.tokenDelay = 120; // in seconds
|
|
74
65
|
|
|
75
66
|
// private props
|
|
76
67
|
this.primaryActions = [];
|
|
@@ -80,21 +71,52 @@ export default class IABookActions extends LitElement {
|
|
|
80
71
|
this.lendingOptions = {};
|
|
81
72
|
this.borrowType = ''; // (browsed|borrowed)
|
|
82
73
|
this.consecutiveLoanCounts = 1; // consecutive loan count
|
|
83
|
-
this.
|
|
84
|
-
this.
|
|
85
|
-
|
|
74
|
+
this.suppressToast = false;
|
|
75
|
+
this.browseTimer = undefined;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* contains one hour auto-loan-renew time configuration
|
|
79
|
+
*
|
|
80
|
+
* @type {object} loanRenewTimeConfig
|
|
81
|
+
* @property {number} loanTotalTime - number of seconds a loan should last
|
|
82
|
+
* @property {number} loanRenewAtLast - check for loan renew at last
|
|
83
|
+
* @property {number} pageChangedInLast - consider loan renew eligible if viewed new page
|
|
84
|
+
* @property {boolean} isDevBox - testing flag
|
|
85
|
+
*/
|
|
86
|
+
this.loanRenewTimeConfig = {};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* contains one hour auto-loan-renew response
|
|
90
|
+
*
|
|
91
|
+
* @type {object} loanRenewResult
|
|
92
|
+
* @property {string} texts - texts messages need to show in toast message
|
|
93
|
+
* @property {boolean} renewNow - key to determine if need to renew now
|
|
94
|
+
* @property {number} secondsLeft - seconds left in active loan
|
|
95
|
+
*/
|
|
96
|
+
this.loanRenewResult = { texts: '', renewNow: false, secondsLeft: 0 };
|
|
86
97
|
|
|
87
|
-
|
|
88
|
-
|
|
98
|
+
/**
|
|
99
|
+
* need showdowRoot opened for resetTimerCountState
|
|
100
|
+
* @see IABookActions::resetTimerCountState
|
|
101
|
+
*/
|
|
102
|
+
this._shadowRoot = this.attachShadow({ mode: 'open' });
|
|
89
103
|
}
|
|
90
104
|
|
|
91
105
|
disconnectedCallback() {
|
|
92
106
|
this.tokenPoller?.disconnectedInterval();
|
|
93
|
-
window?.Sentry?.captureMessage(
|
|
107
|
+
window?.Sentry?.captureMessage(sentryLogs.disconnectedCallback);
|
|
94
108
|
this.disconnectResizeObserver();
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
firstUpdated() {
|
|
112
|
+
// bind auto loan renew events
|
|
113
|
+
this.bindLoanRenewEvents();
|
|
114
|
+
|
|
115
|
+
// localCache used for auto-loan-renew
|
|
116
|
+
this.localCache = new LocalCache({
|
|
117
|
+
namespace: 'loanRenew',
|
|
118
|
+
});
|
|
119
|
+
|
|
98
120
|
if (!this.sharedObserver) {
|
|
99
121
|
this.sharedObserver = new SharedResizeObserver();
|
|
100
122
|
this.setupResizeObserver();
|
|
@@ -102,86 +124,17 @@ export default class IABookActions extends LitElement {
|
|
|
102
124
|
}
|
|
103
125
|
|
|
104
126
|
updated(changed) {
|
|
105
|
-
console.log(changed)
|
|
106
127
|
if (changed.has('lendingStatus') || changed.has('bwbPurchaseUrl')) {
|
|
107
128
|
this.setupLendingToolbarActions();
|
|
108
129
|
this.update();
|
|
109
130
|
}
|
|
110
131
|
|
|
111
|
-
if (changed.has('autoRenew')) {
|
|
112
|
-
this.resetTimerCountdown = true;
|
|
113
|
-
}
|
|
114
132
|
if (changed.has('sharedObserver')) {
|
|
115
133
|
this.disconnectResizeObserver();
|
|
116
134
|
this.setupResizeObserver();
|
|
117
135
|
}
|
|
118
136
|
}
|
|
119
137
|
|
|
120
|
-
bindAutoRenewEvent() {
|
|
121
|
-
// dispatched this event from timer-countdown
|
|
122
|
-
this.addEventListener('autoRenewAttempt', async event => {
|
|
123
|
-
const isPageFlipped = event.detail.bookPageChange;
|
|
124
|
-
|
|
125
|
-
this.autoRenewObj = await new OneHourAutoRenew(
|
|
126
|
-
isPageFlipped,
|
|
127
|
-
this.identifier,
|
|
128
|
-
this.localCache,
|
|
129
|
-
this.autoRenewConfig,
|
|
130
|
-
this.lendingStatus.user_has_browsed && !this.lendingStatus.browsingExpired
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
this.toastTexts = this.autoRenewObj.toastTexts;
|
|
134
|
-
this.hideToast = this.autoRenewObj.hideToast;
|
|
135
|
-
this.browseAgainNow = this.autoRenewObj.renewNow;
|
|
136
|
-
if (this.browseAgainNow) {
|
|
137
|
-
await this.browseHasRenew();
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async browseHasExpired() {
|
|
143
|
-
const currStatus = { ...this.lendingStatus, browsingExpired: true };
|
|
144
|
-
this.lendingStatus = currStatus;
|
|
145
|
-
|
|
146
|
-
// remove respected key:value
|
|
147
|
-
await this.localCache.delete(`${this.identifier}-loanTime`);
|
|
148
|
-
await this.localCache.delete(`${this.identifier}-pageFlipTime`);
|
|
149
|
-
|
|
150
|
-
// show message after browsed book is expired.
|
|
151
|
-
this.toastTexts = 'This book has been auto-returned due to inactivity.';
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
async browseHasRenew() {
|
|
155
|
-
const currStatus = {
|
|
156
|
-
...this.lendingStatus,
|
|
157
|
-
user_has_browsed: true,
|
|
158
|
-
browsingExpired: false,
|
|
159
|
-
secondsLeftOnLoan: this.autoRenewConfig.totalTime + 1,
|
|
160
|
-
};
|
|
161
|
-
this.lendingStatus = currStatus;
|
|
162
|
-
|
|
163
|
-
this.startBrowseTimer();
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
startBrowseTimer() {
|
|
167
|
-
clearTimeout(this.browserTimer);
|
|
168
|
-
|
|
169
|
-
const {
|
|
170
|
-
browsingExpired,
|
|
171
|
-
user_has_browsed,
|
|
172
|
-
secondsLeftOnLoan,
|
|
173
|
-
} = this.lendingStatus;
|
|
174
|
-
if (!user_has_browsed || browsingExpired) {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// expired book and show browse again button
|
|
179
|
-
const timeLeft = secondsLeftOnLoan * 1000;
|
|
180
|
-
this.browserTimer = setTimeout(() => {
|
|
181
|
-
this.browseHasExpired();
|
|
182
|
-
}, timeLeft);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
138
|
/** SharedObserver resize handler */
|
|
186
139
|
handleResize(entry) {
|
|
187
140
|
// if you are observing multiple targets,
|
|
@@ -215,6 +168,8 @@ export default class IABookActions extends LitElement {
|
|
|
215
168
|
/** End SharedObserver resize handler */
|
|
216
169
|
|
|
217
170
|
async setupLendingToolbarActions() {
|
|
171
|
+
this.suppressToast = false;
|
|
172
|
+
|
|
218
173
|
this.lendingOptions = new GetLendingActions(
|
|
219
174
|
this.userid,
|
|
220
175
|
this.identifier,
|
|
@@ -235,13 +190,14 @@ export default class IABookActions extends LitElement {
|
|
|
235
190
|
});
|
|
236
191
|
|
|
237
192
|
this.borrowType = actions.borrowType;
|
|
238
|
-
this.remainingTime = this.lendingStatus.secondsLeftOnLoan;
|
|
239
193
|
|
|
240
194
|
const hasExpired =
|
|
241
195
|
'browsingExpired' in this.lendingStatus &&
|
|
242
196
|
this.lendingStatus?.browsingExpired;
|
|
243
197
|
if (hasExpired) {
|
|
244
|
-
|
|
198
|
+
if (!this.tokenPoller) {
|
|
199
|
+
window?.Sentry?.captureMessage(sentryLogs.bookWasExpired);
|
|
200
|
+
}
|
|
245
201
|
this.tokenPoller?.disconnectedInterval();
|
|
246
202
|
/** Global event - always fire */
|
|
247
203
|
this.dispatchEvent(
|
|
@@ -251,12 +207,13 @@ export default class IABookActions extends LitElement {
|
|
|
251
207
|
composed: true,
|
|
252
208
|
})
|
|
253
209
|
);
|
|
210
|
+
|
|
211
|
+
// early return if book is already expired
|
|
254
212
|
return;
|
|
255
213
|
}
|
|
256
214
|
|
|
257
215
|
if (this.borrowType === 'browsed') {
|
|
258
216
|
// start timer for browsed.
|
|
259
|
-
// when browse is completed, we shows browse-again button
|
|
260
217
|
this.startBrowseTimer();
|
|
261
218
|
}
|
|
262
219
|
|
|
@@ -266,7 +223,212 @@ export default class IABookActions extends LitElement {
|
|
|
266
223
|
return;
|
|
267
224
|
}
|
|
268
225
|
|
|
269
|
-
|
|
226
|
+
// initial timer state for 1-hour loan
|
|
227
|
+
if (this.borrowType === 'browsed' && !this.loanRenewResult.renewNow) {
|
|
228
|
+
setTimeout(() => {
|
|
229
|
+
this.resetTimerCountState();
|
|
230
|
+
}, 100);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* tokenPoller determines if user has loan token for this book
|
|
235
|
+
* - if book is going to renew, need to wait until renew is completed
|
|
236
|
+
* - otherwise execute immediately
|
|
237
|
+
*/
|
|
238
|
+
setTimeout(
|
|
239
|
+
() => {
|
|
240
|
+
this.startLoanTokenPoller();
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
// if book is renew while reading, let's wait to execute create-token api
|
|
244
|
+
this.loanRenewResult.renewNow ? this.tokenDelay * 1000 : 100
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Bind 1 hour loan auto renew event,
|
|
250
|
+
* There are two events we want to use,
|
|
251
|
+
* 1. BookReader:userAction - dispatched from bookreader side
|
|
252
|
+
* 2. click event to refresh the page when book is auto expired
|
|
253
|
+
* 3. IABookActions:loanRenew - dispatched from timer-countdown component
|
|
254
|
+
*/
|
|
255
|
+
bindLoanRenewEvents() {
|
|
256
|
+
/**
|
|
257
|
+
* dispatched this event from bookreader page changed
|
|
258
|
+
*/
|
|
259
|
+
window.addEventListener('BookReader:userAction', () => {
|
|
260
|
+
if (this.borrowType === 'browsed') {
|
|
261
|
+
console.log('user-action executed!');
|
|
262
|
+
this.autoLoanRenewChecker(true);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return nothing;
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* detect click-event on document to close toast-template
|
|
270
|
+
*/
|
|
271
|
+
document.addEventListener('click', e => {
|
|
272
|
+
if (this.loanRenewHelper && this.loanRenewResult.secondsLeft > 0) {
|
|
273
|
+
console.log('clicked-outside');
|
|
274
|
+
this.suppressToast = true;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// reload when user click on book-page and book is EXPIRED
|
|
278
|
+
const hasExpired =
|
|
279
|
+
'browsingExpired' in this.lendingStatus &&
|
|
280
|
+
this.lendingStatus?.browsingExpired;
|
|
281
|
+
if (hasExpired && e.target.nodeName !== 'IA-BOOK-ACTIONS') {
|
|
282
|
+
window.location?.reload();
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* this event dispatched from timer-countdown component for:
|
|
288
|
+
* 1. user turned book page after showing auto-returned warning message
|
|
289
|
+
* 2. show warning message having remaining time
|
|
290
|
+
* @see TimerCountdown::timerCountdown
|
|
291
|
+
*/
|
|
292
|
+
this.addEventListener('IABookActions:loanRenew', async event => {
|
|
293
|
+
await this.autoLoanRenewChecker(false);
|
|
294
|
+
|
|
295
|
+
// show warning message with remaining time to auto returned it.
|
|
296
|
+
if (this.loanRenewResult.renewNow === false) {
|
|
297
|
+
this.loanRenewResult.secondsLeft = event.detail.secondsLeft;
|
|
298
|
+
this.showToastMessage();
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* To determine if need to be renewed browsed book
|
|
305
|
+
* @see LoanRenewHelper
|
|
306
|
+
*
|
|
307
|
+
* @param {Boolean} hasPageChanged
|
|
308
|
+
*/
|
|
309
|
+
async autoLoanRenewChecker(hasPageChanged = false) {
|
|
310
|
+
this.loanRenewHelper = new LoanRenewHelper(
|
|
311
|
+
hasPageChanged,
|
|
312
|
+
this.identifier,
|
|
313
|
+
this.localCache,
|
|
314
|
+
this.loanRenewTimeConfig
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
await this.loanRenewHelper.handleLoanRenew();
|
|
318
|
+
this.loanRenewResult = this.loanRenewHelper.result;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Show toast messages on some specific loan renew features. e.g.
|
|
323
|
+
* - show message when book is auto renewed
|
|
324
|
+
* - show message when book is expired
|
|
325
|
+
* - show message having remaining time when book is about to auto returned
|
|
326
|
+
*/
|
|
327
|
+
async showToastMessage() {
|
|
328
|
+
if (this.suppressToast) return;
|
|
329
|
+
|
|
330
|
+
const iaBookActions = document.querySelector('ia-book-actions')?.shadowRoot;
|
|
331
|
+
if (!iaBookActions) return;
|
|
332
|
+
|
|
333
|
+
let toastTemplate = iaBookActions.querySelector('toast-template');
|
|
334
|
+
if (!toastTemplate) {
|
|
335
|
+
toastTemplate = document.createElement('toast-template');
|
|
336
|
+
}
|
|
337
|
+
await iaBookActions.appendChild(toastTemplate);
|
|
338
|
+
|
|
339
|
+
const config = new ToastConfig();
|
|
340
|
+
config.dismisOnClick = true;
|
|
341
|
+
config.texts = this.loanRenewHelper?.getMessageTexts(
|
|
342
|
+
this.loanRenewResult.texts,
|
|
343
|
+
this.loanRenewResult.secondsLeft
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
toastTemplate.showToast({
|
|
347
|
+
config,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async browseHasRenew() {
|
|
352
|
+
const loanTime = await this.localCache.get(`${this.identifier}-loanTime`);
|
|
353
|
+
const secondsLeft = (loanTime - new Date()) / 1000; // different in seconds
|
|
354
|
+
|
|
355
|
+
const currStatus = {
|
|
356
|
+
...this.lendingStatus,
|
|
357
|
+
user_has_browsed: true,
|
|
358
|
+
browsingExpired: false,
|
|
359
|
+
secondsLeftOnLoan: secondsLeft,
|
|
360
|
+
};
|
|
361
|
+
this.lendingStatus = currStatus;
|
|
362
|
+
|
|
363
|
+
this.startBrowseTimer();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
startBrowseTimer() {
|
|
367
|
+
clearTimeout(this.browseTimer);
|
|
368
|
+
const {
|
|
369
|
+
browsingExpired,
|
|
370
|
+
user_has_browsed,
|
|
371
|
+
secondsLeftOnLoan,
|
|
372
|
+
} = this.lendingStatus;
|
|
373
|
+
if (!user_has_browsed || browsingExpired) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
this.browseTimer = setTimeout(() => {
|
|
378
|
+
this.browseHasExpired();
|
|
379
|
+
}, secondsLeftOnLoan * 1000);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Execute when loan is expired
|
|
384
|
+
*/
|
|
385
|
+
async browseHasExpired() {
|
|
386
|
+
this.tokenPoller?.disconnectedInterval();
|
|
387
|
+
|
|
388
|
+
const currStatus = { ...this.lendingStatus, browsingExpired: true };
|
|
389
|
+
this.lendingStatus = currStatus;
|
|
390
|
+
|
|
391
|
+
// remove respected key:value for loan-renew
|
|
392
|
+
await this.localCache.delete(`${this.identifier}-loanTime`);
|
|
393
|
+
await this.localCache.delete(`${this.identifier}-pageChangedTime`);
|
|
394
|
+
|
|
395
|
+
// show message after browsed book is expired.
|
|
396
|
+
this.loanRenewResult.renewNow = false;
|
|
397
|
+
this.loanRenewResult.texts =
|
|
398
|
+
'This book has been automatically returned due to inactivity.';
|
|
399
|
+
|
|
400
|
+
this.suppressToast = false;
|
|
401
|
+
this.showToastMessage();
|
|
402
|
+
|
|
403
|
+
window?.Sentry?.captureMessage(sentryLogs.browseHasExpired);
|
|
404
|
+
console.log(sentryLogs.browseHasExpired);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Reset timer animation state after book renewed
|
|
409
|
+
*/
|
|
410
|
+
async resetTimerCountState() {
|
|
411
|
+
const timerCountdown = this._shadowRoot.querySelector('timer-countdown');
|
|
412
|
+
if (!timerCountdown) return;
|
|
413
|
+
|
|
414
|
+
const secondsLeft = Number(this.lendingStatus.secondsLeftOnLoan);
|
|
415
|
+
const strokeDashOffset =
|
|
416
|
+
(secondsLeft / this.loanRenewTimeConfig.loanTotalTime) * 315;
|
|
417
|
+
|
|
418
|
+
// set seconds left in loan expire
|
|
419
|
+
timerCountdown.style?.setProperty('--secondsLeftOnLoan', `${secondsLeft}s`);
|
|
420
|
+
|
|
421
|
+
// set circle stroke offset left in loan expire
|
|
422
|
+
timerCountdown.style?.setProperty(
|
|
423
|
+
'--strokeLeftOnLoan',
|
|
424
|
+
`${Number(strokeDashOffset)}` // the perimeter of the circle = (π * 2 * radius)
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
const animationCircle = timerCountdown.shadowRoot.querySelector('.circle');
|
|
428
|
+
animationCircle.style.animationName = 'none';
|
|
429
|
+
setTimeout(() => {
|
|
430
|
+
animationCircle.style.animationName = 'circletimer';
|
|
431
|
+
}, 100);
|
|
270
432
|
}
|
|
271
433
|
|
|
272
434
|
render() {
|
|
@@ -291,26 +453,15 @@ export default class IABookActions extends LitElement {
|
|
|
291
453
|
get timerCountdownTemplate() {
|
|
292
454
|
return this.borrowType === 'browsed'
|
|
293
455
|
? html`<timer-countdown
|
|
294
|
-
|
|
295
|
-
.
|
|
296
|
-
|
|
456
|
+
.secondsLeftOnLoan=${Number(this.lendingStatus.secondsLeftOnLoan)}
|
|
457
|
+
.loanRenewAtLast=${this.loanRenewTimeConfig.loanRenewAtLast}
|
|
458
|
+
.isDevBox=${this.loanRenewTimeConfig.isDevBox}
|
|
297
459
|
></timer-countdown>`
|
|
298
460
|
: nothing;
|
|
299
461
|
}
|
|
300
462
|
|
|
301
|
-
get toastMessageTemplate() {
|
|
302
|
-
return html`
|
|
303
|
-
<toast-message
|
|
304
|
-
.texts=${this.toastTexts}
|
|
305
|
-
?dismisOnClick=${true}
|
|
306
|
-
?hideToast=${this.hideToast}
|
|
307
|
-
></toast-message>
|
|
308
|
-
`;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
463
|
get bookActionBar() {
|
|
312
464
|
return html`
|
|
313
|
-
<button @click=${() => this.pageFlipEvent()}>Page Flip</button>
|
|
314
465
|
<collapsible-action-group
|
|
315
466
|
.userid=${this.userid}
|
|
316
467
|
.identifier=${this.identifier}
|
|
@@ -320,39 +471,56 @@ export default class IABookActions extends LitElement {
|
|
|
320
471
|
.width=${this.width}
|
|
321
472
|
.borrowType=${this.borrowType}
|
|
322
473
|
.returnUrl=${this.returnUrl}
|
|
323
|
-
.
|
|
324
|
-
.
|
|
474
|
+
.localCache=${this.localCache}
|
|
475
|
+
.loanTotalTime=${this.loanRenewTimeConfig.loanTotalTime}
|
|
325
476
|
?hasAdminAccess=${this.hasAdminAccess}
|
|
326
477
|
?disabled=${this.disableActionGroup}
|
|
327
|
-
?
|
|
478
|
+
?renewNow=${this.loanRenewResult.renewNow}
|
|
479
|
+
@loanAutoRenewed=${this.handleLoanAutoRenewed}
|
|
328
480
|
@lendingActionError=${this.handleLendingActionError}
|
|
329
481
|
@toggleActionGroup=${this.handleToggleActionGroup}
|
|
330
482
|
>
|
|
331
483
|
</collapsible-action-group>
|
|
332
484
|
${this.textGroupTemplate} ${this.infoIconTemplate}
|
|
333
|
-
${this.timerCountdownTemplate}
|
|
485
|
+
${this.timerCountdownTemplate}
|
|
334
486
|
`;
|
|
335
487
|
}
|
|
336
488
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
);
|
|
346
|
-
|
|
489
|
+
/**
|
|
490
|
+
* Execute after auto loan renewed is completed
|
|
491
|
+
* - show success message
|
|
492
|
+
* - then change the remaining time
|
|
493
|
+
* - reset timer state
|
|
494
|
+
*/
|
|
495
|
+
async handleLoanAutoRenewed() {
|
|
496
|
+
if (this.loanRenewResult.renewNow) {
|
|
497
|
+
this.tokenPoller?.disconnectedInterval();
|
|
498
|
+
|
|
499
|
+
this.suppressToast = false;
|
|
500
|
+
await this.showToastMessage();
|
|
501
|
+
await this.browseHasRenew();
|
|
502
|
+
await this.resetTimerCountState();
|
|
503
|
+
|
|
504
|
+
window?.Sentry?.captureMessage(`${sentryLogs.bookHasRenewed}`);
|
|
505
|
+
// analytics?? for consecutive renew.....
|
|
506
|
+
|
|
507
|
+
// testing console....
|
|
508
|
+
console.log(sentryLogs.bookHasRenewed, {
|
|
509
|
+
loanRenewResult: this.loanRenewResult,
|
|
510
|
+
browseHasRenew: this.lendingStatus.secondsLeftOnLoan,
|
|
511
|
+
resetTimerCountState: this._shadowRoot.querySelector('timer-countdown'),
|
|
512
|
+
});
|
|
513
|
+
}
|
|
347
514
|
}
|
|
348
515
|
|
|
349
516
|
/**
|
|
350
517
|
* enable access of borrowed/browsed books
|
|
518
|
+
* @see LoanTokenPoller
|
|
351
519
|
*/
|
|
352
520
|
startLoanTokenPoller() {
|
|
353
521
|
if (this.tokenPoller) {
|
|
354
|
-
window?.Sentry?.captureMessage(
|
|
355
|
-
this.tokenPoller
|
|
522
|
+
window?.Sentry?.captureMessage(sentryLogs.clearTokenPoller);
|
|
523
|
+
this.tokenPoller?.disconnectedInterval();
|
|
356
524
|
}
|
|
357
525
|
const successCallback = () => {
|
|
358
526
|
this.lendingBarPostInit();
|
|
@@ -377,7 +545,7 @@ export default class IABookActions extends LitElement {
|
|
|
377
545
|
this.borrowType,
|
|
378
546
|
successCallback,
|
|
379
547
|
errorCallback,
|
|
380
|
-
this.tokenDelay //
|
|
548
|
+
this.tokenDelay // in seconds
|
|
381
549
|
);
|
|
382
550
|
}
|
|
383
551
|
|
|
@@ -408,6 +576,20 @@ export default class IABookActions extends LitElement {
|
|
|
408
576
|
|
|
409
577
|
if (errorMsg) this.showErrorModal(errorMsg, action);
|
|
410
578
|
|
|
579
|
+
// if error related to loan token
|
|
580
|
+
// - clear tokenPoller interval
|
|
581
|
+
// - set user_has_browsed to `false`
|
|
582
|
+
if (action === 'create_token') {
|
|
583
|
+
this.tokenPoller?.disconnectedInterval();
|
|
584
|
+
|
|
585
|
+
const currStatus = {
|
|
586
|
+
...this.lendingStatus,
|
|
587
|
+
user_has_browsed: false,
|
|
588
|
+
available_to_browse: true,
|
|
589
|
+
};
|
|
590
|
+
this.lendingStatus = currStatus;
|
|
591
|
+
}
|
|
592
|
+
|
|
411
593
|
// update action bar state if book is not available to browse or borrow.
|
|
412
594
|
if (errorMsg && errorMsg.match(/not available to borrow/gm)) {
|
|
413
595
|
let currStatus = this.lendingStatus;
|
|
@@ -463,7 +645,8 @@ export default class IABookActions extends LitElement {
|
|
|
463
645
|
href="mailto:info@archive.org?subject=Help: cannot access my borrowed book: ${this
|
|
464
646
|
.identifier}"
|
|
465
647
|
>info@archive.org</a
|
|
466
|
-
|
|
648
|
+
><br /><br />
|
|
649
|
+
errorLog: ${errorMsg}`;
|
|
467
650
|
}
|
|
468
651
|
|
|
469
652
|
this.modal.showModal({
|
|
@@ -484,11 +667,13 @@ export default class IABookActions extends LitElement {
|
|
|
484
667
|
}
|
|
485
668
|
|
|
486
669
|
get textGroupTemplate() {
|
|
487
|
-
return
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
670
|
+
return this.primaryTitle
|
|
671
|
+
? html`<text-group
|
|
672
|
+
textClass=${this.textClass}
|
|
673
|
+
.texts=${this.primaryTitle}
|
|
674
|
+
>
|
|
675
|
+
</text-group>`
|
|
676
|
+
: nothing;
|
|
492
677
|
}
|
|
493
678
|
|
|
494
679
|
get hasAdminAccess() {
|
|
@@ -499,20 +684,23 @@ export default class IABookActions extends LitElement {
|
|
|
499
684
|
return css`
|
|
500
685
|
:host {
|
|
501
686
|
display: block;
|
|
502
|
-
background: var(--primaryBGColor, #000);
|
|
503
|
-
color: var(--primaryTextColor, #fff);
|
|
504
687
|
}
|
|
688
|
+
|
|
505
689
|
.lending-wrapper {
|
|
506
690
|
width: 100%;
|
|
507
691
|
margin: 0 auto;
|
|
692
|
+
background: var(--primaryBGColor, #000);
|
|
693
|
+
color: var(--primaryTextColor, #fff);
|
|
508
694
|
display: inline-flex;
|
|
509
695
|
align-items: center;
|
|
510
696
|
justify-content: center;
|
|
511
697
|
flex-wrap: wrap;
|
|
512
698
|
}
|
|
513
699
|
|
|
514
|
-
toast-
|
|
515
|
-
--
|
|
700
|
+
toast-template {
|
|
701
|
+
--toastTopMargin: 80px;
|
|
702
|
+
--toastBGColor: #333;
|
|
703
|
+
--toastFontColor: #fff;
|
|
516
704
|
}
|
|
517
705
|
`;
|
|
518
706
|
}
|
|
@@ -6,7 +6,7 @@ const container = ({
|
|
|
6
6
|
{
|
|
7
7
|
analyticsEvent: { action: 'Browse', category: 'Lending' },
|
|
8
8
|
className: 'ia-button primary',
|
|
9
|
-
text: 'Borrow
|
|
9
|
+
text: 'Borrow',
|
|
10
10
|
id: 'browseBook',
|
|
11
11
|
},
|
|
12
12
|
{
|
|
@@ -40,7 +40,7 @@ describe('<collapsible-action-group>', () => {
|
|
|
40
40
|
.true;
|
|
41
41
|
|
|
42
42
|
const primaryButton = primaryActionContainer.querySelector('.ia-button');
|
|
43
|
-
expect(primaryButton.innerText).to.equal('Borrow
|
|
43
|
+
expect(primaryButton.innerText).to.equal('Borrow');
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
it('check if loader is active and action-group is disabled', async () => {
|