@internetarchive/ia-book-actions 0.1.11-b9 → 1.1.0-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 +58 -0
- package/package.json +4 -3
- package/src/components/collapsible-action-group.js +5 -4
- package/src/components/timer-countdown.js +44 -51
- package/src/core/config/constants.js +1 -1
- package/src/core/config/ia-lending-intervals.js +19 -5
- package/src/core/services/actions-config.js +0 -2
- package/src/core/services/actions-handler/actions-handler-service.js +14 -3
- package/src/core/services/actions-handler/actions-handler.js +49 -22
- package/src/core/services/get-lending-actions.js +2 -2
- package/src/core/services/loan-analytics.js +3 -2
- package/src/core/services/loan-renew-helper.js +2 -1
- package/src/core/services/loan-token-poller.js +1 -0
- package/src/core/services/log.js +16 -0
- package/src/ia-book-actions.js +188 -176
- package/test/core/services/loan-token-poller.test.js +13 -1
- package/test/ia-book-actions.test.js +102 -13
package/demo/index.html
CHANGED
|
@@ -150,6 +150,25 @@
|
|
|
150
150
|
});
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
+
document.querySelectorAll('.searchParam input[type=checkbox]').forEach((item) => {
|
|
154
|
+
item.addEventListener('click', (e) => {
|
|
155
|
+
var searchParams = new URLSearchParams(window.location.search);
|
|
156
|
+
var separate = '';
|
|
157
|
+
if (e.target.checked) {
|
|
158
|
+
separate = '?';
|
|
159
|
+
searchParams.set('q', 'test');
|
|
160
|
+
} else {
|
|
161
|
+
separate = '';
|
|
162
|
+
searchParams.delete('q');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (history.pushState) {
|
|
166
|
+
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + separate + searchParams;
|
|
167
|
+
window.history.pushState({path:newurl},'',newurl);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
153
172
|
document.querySelectorAll('.errorEnable input[type=checkbox]').forEach((item) => {
|
|
154
173
|
if (window.location.href.indexOf('?error=true') !== -1) {
|
|
155
174
|
item.checked = true;
|
|
@@ -242,6 +261,31 @@
|
|
|
242
261
|
});
|
|
243
262
|
});
|
|
244
263
|
|
|
264
|
+
document.querySelector('#show_warning_modal').addEventListener('click', async () => {
|
|
265
|
+
if (!iaBookActions.lendingStatus.user_has_browsed) {
|
|
266
|
+
const newLendingStatus = { ...iaBookActions.lendingStatus, user_has_browsed: true };
|
|
267
|
+
iaBookActions.lendingStatus = newLendingStatus;
|
|
268
|
+
await iaBookActions.updateComplete;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
iaBookActions.showWarningModal();
|
|
272
|
+
|
|
273
|
+
if (iaBookActions.lendingStatus.user_has_browsed) {
|
|
274
|
+
iaBookActions.showWarningModal();
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
document.querySelector('#show_expired_modal').addEventListener('click', async () => {
|
|
279
|
+
if (!iaBookActions.lendingStatus.user_has_browsed) {
|
|
280
|
+
const newLendingStatus = { ...iaBookActions.lendingStatus, user_has_browsed: true };
|
|
281
|
+
iaBookActions.lendingStatus = newLendingStatus;
|
|
282
|
+
await iaBookActions.updateComplete;
|
|
283
|
+
}
|
|
284
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
285
|
+
|
|
286
|
+
iaBookActions.browseHasExpired();
|
|
287
|
+
});
|
|
288
|
+
|
|
245
289
|
document.querySelectorAll('.availableToBorrow input[type=radio]').forEach((item) => {
|
|
246
290
|
item.addEventListener('click', (e) => {
|
|
247
291
|
if (e.target.value === 'available_to_borrow') {
|
|
@@ -298,6 +342,11 @@
|
|
|
298
342
|
})
|
|
299
343
|
);
|
|
300
344
|
})
|
|
345
|
+
|
|
346
|
+
// listen for IABookReader:BrowsingHasExpired
|
|
347
|
+
window.addEventListener('IABookReader:BrowsingHasExpired', () => {
|
|
348
|
+
console.log('IABookReader:BrowsingHasExpired EVENT FIRED');
|
|
349
|
+
});
|
|
301
350
|
</script>
|
|
302
351
|
|
|
303
352
|
<div>
|
|
@@ -308,6 +357,8 @@
|
|
|
308
357
|
<td class="titleBar">
|
|
309
358
|
<label><input type="checkbox" name="title" value="title" />Title Bar</label>
|
|
310
359
|
</td>
|
|
360
|
+
<td class="searchParam">
|
|
361
|
+
<label><input type="checkbox" name="search" value="Search Param" />Search Param</label>
|
|
311
362
|
<td>
|
|
312
363
|
<button class="pageChangedEvent">Page Change Event</button>
|
|
313
364
|
</td>
|
|
@@ -334,6 +385,13 @@
|
|
|
334
385
|
<label><input type="radio" name="browse" value="available_to_browse" />available_to_browse</label>
|
|
335
386
|
<label><input type="radio" name="browse" value="user_has_browsed" />user_has_browsed</label>
|
|
336
387
|
<label><input type="radio" name="browse" value="browsingExpired" />browsingExpired</label>
|
|
388
|
+
<div>
|
|
389
|
+
<button id="show_warning_modal">When Browsing (`user_has_browsed`), show Warning Modal</button>
|
|
390
|
+
</div>
|
|
391
|
+
<div>
|
|
392
|
+
<button id="show_expired_modal">While Browsing (`user_has_browsed`), Expire book & show its modal</button>
|
|
393
|
+
how_expired_modal
|
|
394
|
+
</div>
|
|
337
395
|
</td>
|
|
338
396
|
<td class="availableToBorrow">
|
|
339
397
|
<label><input type="radio" name="borrow" value="available_to_borrow" />available_to_borrow</label>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@internetarchive/ia-book-actions",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0-alpha1",
|
|
4
4
|
"description": "Bookreader actions for borrowable book",
|
|
5
5
|
"author": "Internet Archive",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -18,13 +18,14 @@
|
|
|
18
18
|
"test:watch": "web-test-runner --watch --playwright --browsers chromium firefox webkit"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@internetarchive/ia-activity-indicator": "^0.0.4",
|
|
22
21
|
"@internetarchive/icon-info": "^1.2.6",
|
|
23
22
|
"@internetarchive/local-cache": "^0.2.1",
|
|
24
23
|
"@internetarchive/modal-manager": "^0.2.12",
|
|
25
24
|
"@internetarchive/shared-resize-observer": "^0.2.0",
|
|
26
25
|
"@internetarchive/toast-manager": "0.1.0",
|
|
27
|
-
"
|
|
26
|
+
"install-deps": "^1.1.0",
|
|
27
|
+
"lit": "^2.5.0",
|
|
28
|
+
"playwright": "^1.43.1"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@open-wc/eslint-config": "^4.2.0",
|
|
@@ -63,15 +63,16 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
63
63
|
this.resetActions();
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
if (changed.has('autoRenew') && this.autoRenew
|
|
66
|
+
if (changed.has('autoRenew') && this.autoRenew) {
|
|
67
67
|
this.dispatchLoanEvent('autoRenew');
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
const requestingAutoreturn = changed.has('autoReturn') && this.autoReturn;
|
|
71
|
+
if (requestingAutoreturn) {
|
|
71
72
|
this.dispatchLoanEvent('autoReturn');
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
if (changed.has('returnNow') && this.returnNow
|
|
75
|
+
if (changed.has('returnNow') && this.returnNow && !requestingAutoreturn) {
|
|
75
76
|
this.dispatchLoanEvent('returnNow', { borrowType: 'browse' });
|
|
76
77
|
}
|
|
77
78
|
}
|
|
@@ -177,7 +178,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
177
178
|
get renderSecondaryActions() {
|
|
178
179
|
if (!this.secondaryActions.length) return nothing;
|
|
179
180
|
|
|
180
|
-
return this.secondaryActions.map(action => this.
|
|
181
|
+
return this.secondaryActions.map(action => this.renderActionButton(action));
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
/**
|
|
@@ -3,32 +3,43 @@ import { html, css, LitElement } from 'lit';
|
|
|
3
3
|
export default class TimerCountdown extends LitElement {
|
|
4
4
|
static get properties() {
|
|
5
5
|
return {
|
|
6
|
-
secondsLeftOnLoan: { type: Number },
|
|
6
|
+
secondsLeftOnLoan: { type: Number },
|
|
7
|
+
displayTime: { type: Boolean },
|
|
7
8
|
};
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
constructor() {
|
|
11
12
|
super();
|
|
12
13
|
|
|
13
|
-
/**
|
|
14
|
-
* seconds left in current loan
|
|
15
|
-
* @type {number}
|
|
16
|
-
*/
|
|
17
14
|
this.secondsLeftOnLoan = 0;
|
|
15
|
+
this.displayTime = false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get minutesLeftOnLoan() {
|
|
19
|
+
let timeLeft = Math.round(this.secondsLeftOnLoan);
|
|
20
|
+
|
|
21
|
+
// convert time from second to minute
|
|
22
|
+
timeLeft = Math.ceil(timeLeft / 60);
|
|
23
|
+
|
|
24
|
+
if (timeLeft < 10) {
|
|
25
|
+
timeLeft = `0:0${timeLeft}`;
|
|
26
|
+
} else if (timeLeft === 60) {
|
|
27
|
+
timeLeft = `1:00`;
|
|
28
|
+
} else {
|
|
29
|
+
timeLeft = `0:${timeLeft}`;
|
|
30
|
+
}
|
|
31
|
+
return timeLeft;
|
|
18
32
|
}
|
|
19
33
|
|
|
20
34
|
/**
|
|
21
35
|
* get remaining time with timeunit
|
|
22
36
|
*
|
|
23
37
|
* @memberof TimerCountdown
|
|
24
|
-
* @return string
|
|
38
|
+
* @return string - minutes left
|
|
25
39
|
*/
|
|
26
40
|
get remainingTime() {
|
|
27
41
|
const unitOfTime = 'minute';
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// convert time from second to minute
|
|
31
|
-
timeLeft = Math.ceil(timeLeft / 60);
|
|
42
|
+
const timeLeft = this.minutesLeftOnLoan;
|
|
32
43
|
|
|
33
44
|
return timeLeft !== 1
|
|
34
45
|
? `${timeLeft} ${unitOfTime}s`
|
|
@@ -36,58 +47,28 @@ export default class TimerCountdown extends LitElement {
|
|
|
36
47
|
}
|
|
37
48
|
|
|
38
49
|
render() {
|
|
50
|
+
const viewClass = this.displayTime ? 'view' : 'hide';
|
|
39
51
|
return html`
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
<button
|
|
53
|
+
id="timer-counter"
|
|
54
|
+
class=${viewClass}
|
|
55
|
+
@click=${() => {
|
|
56
|
+
this.displayTime = !this.displayTime;
|
|
57
|
+
}}
|
|
58
|
+
role="timer"
|
|
45
59
|
>
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
<span>${this.minutesLeftOnLoan}</span>
|
|
61
|
+
<span class="sr-only">${this.remainingTime} left</span>
|
|
62
|
+
</button>
|
|
49
63
|
`;
|
|
50
64
|
}
|
|
51
65
|
|
|
52
66
|
static get styles() {
|
|
53
|
-
const white = css`var(--white, #fff)`;
|
|
54
|
-
const timerSecondsLeft = css`var(--secondsLeftOnLoan, 6000s)`; //
|
|
55
|
-
const timerStrokeLeft = css`var(--strokeLeftOnLoan, 315)`;
|
|
56
|
-
|
|
57
67
|
return css`
|
|
58
68
|
:host {
|
|
59
69
|
right: 0;
|
|
60
70
|
margin-right: 10px;
|
|
61
71
|
position: absolute;
|
|
62
|
-
height: 20px;
|
|
63
|
-
width: 20px;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
@keyframes circletimer {
|
|
67
|
-
0% {
|
|
68
|
-
stroke-dashoffset: ${timerStrokeLeft};
|
|
69
|
-
stroke-dasharray: 315;
|
|
70
|
-
}
|
|
71
|
-
100% {
|
|
72
|
-
stroke-dashoffset: 0;
|
|
73
|
-
stroke-dasharray: 315;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
svg {
|
|
78
|
-
background-color: ${white};
|
|
79
|
-
border-radius: 50px;
|
|
80
|
-
border: 2px solid ${white};
|
|
81
|
-
transform: rotateZ(-90deg);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
svg .circle {
|
|
85
|
-
stroke: #000;
|
|
86
|
-
stroke-width: 100px;
|
|
87
|
-
fill: ${white};
|
|
88
|
-
stroke-dashoffset: 315;
|
|
89
|
-
stroke-dasharray: 0;
|
|
90
|
-
animation: ${timerSecondsLeft} circletimer linear;
|
|
91
72
|
}
|
|
92
73
|
|
|
93
74
|
.sr-only {
|
|
@@ -100,6 +81,18 @@ export default class TimerCountdown extends LitElement {
|
|
|
100
81
|
border: none;
|
|
101
82
|
overflow: hidden;
|
|
102
83
|
}
|
|
84
|
+
|
|
85
|
+
button#timer-counter {
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.hide {
|
|
90
|
+
opacity: 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.show {
|
|
94
|
+
opacity: 1;
|
|
95
|
+
}
|
|
103
96
|
`;
|
|
104
97
|
}
|
|
105
98
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* global: window */
|
|
1
2
|
/**
|
|
2
3
|
* Collection of methods for managing intervals for lending system
|
|
3
4
|
*
|
|
@@ -18,16 +19,19 @@ window.IALendingIntervals = {
|
|
|
18
19
|
tokenPoller: 0,
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
|
-
*
|
|
22
|
-
* @see TimerCountdown::timerCountdown
|
|
22
|
+
* renewal check interval
|
|
23
23
|
*/
|
|
24
24
|
timerCountdown: 0,
|
|
25
25
|
|
|
26
|
+
/** expiration timer */
|
|
27
|
+
browseExpireTimeout: 0,
|
|
28
|
+
|
|
26
29
|
/**
|
|
27
30
|
* clear interval for create_token api
|
|
28
31
|
*/
|
|
29
32
|
clearTokenPoller: () => {
|
|
30
|
-
window.clearInterval(window
|
|
33
|
+
window.clearInterval(window.IALendingIntervals.tokenPoller);
|
|
34
|
+
window.IALendingIntervals.tokenPoller = 0;
|
|
31
35
|
},
|
|
32
36
|
|
|
33
37
|
/**
|
|
@@ -35,13 +39,23 @@ window.IALendingIntervals = {
|
|
|
35
39
|
*/
|
|
36
40
|
clearTimerCountdown: () => {
|
|
37
41
|
window.clearInterval(window.IALendingIntervals.timerCountdown);
|
|
42
|
+
window.IALendingIntervals.timerCountdown = 0;
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* clear interval for graphic timer for one-hour loan renew
|
|
47
|
+
*/
|
|
48
|
+
clearBrowseExpireTimeout: () => {
|
|
49
|
+
window.clearTimeout(window.IALendingIntervals.browseExpireTimeout);
|
|
50
|
+
window.IALendingIntervals.browseExpireTimeout = 0;
|
|
38
51
|
},
|
|
39
52
|
|
|
40
53
|
/**
|
|
41
54
|
* clear all intervals being used acros lending system
|
|
42
55
|
*/
|
|
43
56
|
clearAll: () => {
|
|
44
|
-
window
|
|
45
|
-
window
|
|
57
|
+
window?.IALendingIntervals?.clearTokenPoller();
|
|
58
|
+
window?.IALendingIntervals?.clearTimerCountdown();
|
|
59
|
+
window?.IALendingIntervals?.clearBrowseExpireTimeout();
|
|
46
60
|
},
|
|
47
61
|
};
|
|
@@ -207,8 +207,6 @@ export default class ActionsConfig {
|
|
|
207
207
|
id: 'adminAccess',
|
|
208
208
|
text: 'Admin Access',
|
|
209
209
|
title: 'You have administrative privileges to read this book',
|
|
210
|
-
url: '?admin=1',
|
|
211
|
-
target: '_self',
|
|
212
210
|
className: 'danger',
|
|
213
211
|
analyticsEvent: {
|
|
214
212
|
category: this.analyticsCategories.adminAccess,
|
|
@@ -21,7 +21,13 @@ export default async function ActionsHandlerService(options) {
|
|
|
21
21
|
const tokenError = 'loan token not found. please try again later.';
|
|
22
22
|
const borrowError =
|
|
23
23
|
'This book is not available to borrow at this time. Please try again later.';
|
|
24
|
-
const erroneousActions = [
|
|
24
|
+
const erroneousActions = [
|
|
25
|
+
'browse_book',
|
|
26
|
+
'borrow_book',
|
|
27
|
+
'create_token',
|
|
28
|
+
'renew_loan',
|
|
29
|
+
'return_loan',
|
|
30
|
+
];
|
|
25
31
|
const shouldReturnError =
|
|
26
32
|
location?.href?.indexOf('?error=true') !== -1 &&
|
|
27
33
|
location?.hostname !== 'archive.org';
|
|
@@ -36,7 +42,7 @@ export default async function ActionsHandlerService(options) {
|
|
|
36
42
|
method: 'POST',
|
|
37
43
|
body: formData,
|
|
38
44
|
})
|
|
39
|
-
.then(response => {
|
|
45
|
+
.then(async response => {
|
|
40
46
|
// intentional error on localhost
|
|
41
47
|
if (shouldReturnError && erroneousActions.includes(option?.action)) {
|
|
42
48
|
return {
|
|
@@ -47,7 +53,12 @@ export default async function ActionsHandlerService(options) {
|
|
|
47
53
|
|
|
48
54
|
// return success response for /demo/ server...
|
|
49
55
|
if (baseHost == '/demo/1' || baseHost == '/demo/') {
|
|
50
|
-
if (
|
|
56
|
+
if (
|
|
57
|
+
option?.action == 'renew_loan' ||
|
|
58
|
+
option?.action == 'return_loan'
|
|
59
|
+
) {
|
|
60
|
+
// wait a few seconds so that the user can see the loading state
|
|
61
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
51
62
|
return {
|
|
52
63
|
success: true,
|
|
53
64
|
loan: { renewal: true },
|
|
@@ -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 log from '../log.js';
|
|
5
6
|
|
|
6
7
|
import ActionsHandlerService from './actions-handler-service.js';
|
|
7
8
|
import LoanAnanlytics from '../loan-analytics.js';
|
|
@@ -38,24 +39,33 @@ export default class ActionsHandler extends LitElement {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
bindEvents() {
|
|
41
|
-
this.addEventListener('browseBook', () => {
|
|
42
|
+
this.addEventListener('browseBook', async () => {
|
|
42
43
|
this.handleBrowseIt();
|
|
43
|
-
this.loanAnanlytics?.storeLoanStatsCount(this.identifier, 'browse');
|
|
44
|
+
await this.loanAnanlytics?.storeLoanStatsCount(this.identifier, 'browse');
|
|
44
45
|
});
|
|
45
46
|
|
|
46
|
-
this.addEventListener('browseBookAgain', () => {
|
|
47
|
+
this.addEventListener('browseBookAgain', async () => {
|
|
47
48
|
this.handleBrowseIt();
|
|
48
|
-
this.loanAnanlytics?.storeLoanStatsCount(
|
|
49
|
+
await this.loanAnanlytics?.storeLoanStatsCount(
|
|
50
|
+
this.identifier,
|
|
51
|
+
'browseagain'
|
|
52
|
+
);
|
|
49
53
|
});
|
|
50
54
|
|
|
51
|
-
this.addEventListener('autoRenew', () => {
|
|
55
|
+
this.addEventListener('autoRenew', async () => {
|
|
52
56
|
this.handleLoanRenewNow();
|
|
53
|
-
this.loanAnanlytics?.storeLoanStatsCount(
|
|
57
|
+
await this.loanAnanlytics?.storeLoanStatsCount(
|
|
58
|
+
this.identifier,
|
|
59
|
+
'autorenew'
|
|
60
|
+
);
|
|
54
61
|
});
|
|
55
62
|
|
|
56
|
-
this.addEventListener('autoReturn', () => {
|
|
63
|
+
this.addEventListener('autoReturn', async () => {
|
|
57
64
|
this.handleReturnIt();
|
|
58
|
-
this.loanAnanlytics?.storeLoanStatsCount(
|
|
65
|
+
await this.loanAnanlytics?.storeLoanStatsCount(
|
|
66
|
+
this.identifier,
|
|
67
|
+
'autoreturn'
|
|
68
|
+
);
|
|
59
69
|
});
|
|
60
70
|
|
|
61
71
|
this.addEventListener('returnNow', ({ detail }) => {
|
|
@@ -105,6 +115,11 @@ export default class ActionsHandler extends LitElement {
|
|
|
105
115
|
this.addEventListener('adminAccess', ({ detail }) => {
|
|
106
116
|
const { category, action } = detail.event;
|
|
107
117
|
this.loanAnanlytics?.sendEvent(category, action, this.identifier);
|
|
118
|
+
|
|
119
|
+
// keep existing params and add new one
|
|
120
|
+
const url = new URL(window.location.href);
|
|
121
|
+
url.searchParams.append('admin', 1);
|
|
122
|
+
window.location.search = url.search;
|
|
108
123
|
});
|
|
109
124
|
|
|
110
125
|
this.addEventListener('exitAdminAccess', ({ detail }) => {
|
|
@@ -142,25 +157,37 @@ export default class ActionsHandler extends LitElement {
|
|
|
142
157
|
action,
|
|
143
158
|
identifier: this.identifier,
|
|
144
159
|
success: data => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
);
|
|
152
|
-
if (data?.success === true && data?.loan?.renewal === true) {
|
|
160
|
+
log('RENEW_LOAN --- ', data, action, data.loan, this.identifier);
|
|
161
|
+
const activeLoan = data.loan ? data.loan : undefined;
|
|
162
|
+
const isRenewal = activeLoan.renewal;
|
|
163
|
+
|
|
164
|
+
if (activeLoan && isRenewal) {
|
|
165
|
+
// when loan is renewed, let's reset timer & let everyone know.
|
|
153
166
|
this.setBrowseTimeSession();
|
|
154
|
-
this.dispatchEvent(
|
|
155
|
-
new CustomEvent('loanAutoRenewed', {
|
|
156
|
-
detail: { action, data },
|
|
157
|
-
})
|
|
158
|
-
);
|
|
159
167
|
} else {
|
|
168
|
+
log('RENEW_LOAN ERROR --- ', {
|
|
169
|
+
action,
|
|
170
|
+
isRenewal,
|
|
171
|
+
activeLoan,
|
|
172
|
+
data,
|
|
173
|
+
id: this.identifier,
|
|
174
|
+
});
|
|
160
175
|
window?.Sentry?.captureMessage(
|
|
161
176
|
`${sentryLogs.bookRenewFailed} - Error: ${JSON.stringify(data)}`
|
|
162
177
|
);
|
|
178
|
+
this.dispatchActionError(action, {
|
|
179
|
+
data,
|
|
180
|
+
error: true,
|
|
181
|
+
message: 'Loan renewal failed: no loan active.',
|
|
182
|
+
});
|
|
163
183
|
}
|
|
184
|
+
|
|
185
|
+
// dispatch outcome of loan renewal
|
|
186
|
+
this.dispatchEvent(
|
|
187
|
+
new CustomEvent('loanAutoRenewed', {
|
|
188
|
+
detail: { action, data: { ...data, loan: activeLoan } },
|
|
189
|
+
})
|
|
190
|
+
);
|
|
164
191
|
},
|
|
165
192
|
error: data => {
|
|
166
193
|
this.dispatchActionError(action, data);
|
|
@@ -322,7 +349,7 @@ export default class ActionsHandler extends LitElement {
|
|
|
322
349
|
// delete pageChangedTime when book is auto renew at nth minute
|
|
323
350
|
await this.localCache.delete(`${this.identifier}-pageChangedTime`);
|
|
324
351
|
} catch (error) {
|
|
325
|
-
|
|
352
|
+
log(error);
|
|
326
353
|
}
|
|
327
354
|
}
|
|
328
355
|
|
|
@@ -40,7 +40,7 @@ import ActionsConfig from './actions-config.js';
|
|
|
40
40
|
* @enum {string}
|
|
41
41
|
*/
|
|
42
42
|
export const bookTitles = {
|
|
43
|
-
available_1hr: 'Renews automatically
|
|
43
|
+
available_1hr: 'Renews automatically with continued use.',
|
|
44
44
|
available_14d: 'This book can be borrowed for 14 days.',
|
|
45
45
|
available_pd: 'Book available to patrons with print disabilities.',
|
|
46
46
|
available_waitlist: 'A waitlist is available.',
|
|
@@ -49,7 +49,7 @@ export const bookTitles = {
|
|
|
49
49
|
being_borrowed: 'Another patron is using this book. Please check back later.',
|
|
50
50
|
eligible_pd: 'You are eligible for print-disabled access.',
|
|
51
51
|
on_waitlist: 'You are on the waitlist for this book.',
|
|
52
|
-
session_expired: 'Renews automatically
|
|
52
|
+
session_expired: 'Renews automatically with continued use.',
|
|
53
53
|
unavailable: 'This book is not available at this time.',
|
|
54
54
|
};
|
|
55
55
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { analyticsCategories } from '../config/analytics-event-and-category.js';
|
|
4
4
|
import * as Cookies from './doc-cookies.js';
|
|
5
|
+
import log from './log.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* This class is used to send different GA events for loan system.
|
|
@@ -45,7 +46,7 @@ export default class LoanAnanlytics {
|
|
|
45
46
|
'/'
|
|
46
47
|
);
|
|
47
48
|
} catch (error) {
|
|
48
|
-
|
|
49
|
+
log(error);
|
|
49
50
|
this.sendEvent('Cookies-Error-Actions', error, this.identifier);
|
|
50
51
|
}
|
|
51
52
|
}
|
|
@@ -144,7 +145,7 @@ export default class LoanAnanlytics {
|
|
|
144
145
|
* @memberof LoanAnanlytics
|
|
145
146
|
*/
|
|
146
147
|
sendEvent(eventCategory, eventAction, label, extraParams) {
|
|
147
|
-
//
|
|
148
|
+
// log(
|
|
148
149
|
// 'eventCategory:-',
|
|
149
150
|
// eventCategory,
|
|
150
151
|
// '\t||\teventAction:-',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable class-methods-use-this */
|
|
2
2
|
|
|
3
3
|
import { nothing } from 'lit';
|
|
4
|
+
import log from './log.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* This class is used to determine if use is eligible for auto renew loan.
|
|
@@ -32,7 +33,7 @@ export class LoanRenewHelper {
|
|
|
32
33
|
}
|
|
33
34
|
return this.autoChecker(); // auto checker at last 10th minute
|
|
34
35
|
} catch (error) {
|
|
35
|
-
|
|
36
|
+
log(error);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
return nothing;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* eslint-disable no-restricted-globals */
|
|
2
|
+
/* eslint-disable semi */
|
|
3
|
+
/**
|
|
4
|
+
* log() utility -- production ignores 'log()' JS calls; dev invokes 'log()'
|
|
5
|
+
*/
|
|
6
|
+
const log =
|
|
7
|
+
location.hostname === 'localhost' ||
|
|
8
|
+
location.host.match(/^(www|cat)-[a-z0-9]+\.archive\.org$/) ||
|
|
9
|
+
location.host.match(/\.code\.archive\.org$/) ||
|
|
10
|
+
location.host.match(/\.dev\.archive\.org$/) ||
|
|
11
|
+
location.host.match(/^ia-petabox-/)
|
|
12
|
+
? // eslint-disable-next-line no-console
|
|
13
|
+
console.log.bind(console) // convenient, no? Stateless function
|
|
14
|
+
: () => {};
|
|
15
|
+
|
|
16
|
+
export { log as default };
|