@internetarchive/ia-book-actions 0.0.29 → 0.1.0
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 +55 -10
- package/package.json +5 -4
- package/src/assets/styles/collapsible-action-group.js +2 -1
- package/src/components/collapsible-action-group.js +27 -0
- package/src/components/info-icon.js +0 -9
- package/src/components/text-group.js +1 -1
- package/src/components/timer-countdown.js +178 -0
- 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 +63 -5
- package/src/core/services/get-lending-actions.js +6 -11
- package/src/core/services/loan-renew-helper.js +161 -0
- package/src/core/services/loan-token-poller.js +19 -10
- package/src/ia-book-actions.js +339 -41
- package/test/components/collapsible-action-group.test.js +2 -2
- package/test/components/timer-countdown.test.js +45 -0
- package/test/core/services/get-lending-actions.test.js +4 -4
- package/test/core/services/loan-renew-helper.test.js +86 -0
- package/test/ia-book-actions.test.js +75 -12
package/demo/index.html
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
16
16
|
}
|
|
17
17
|
#demo {
|
|
18
|
-
height:
|
|
18
|
+
height: 100px;
|
|
19
19
|
}
|
|
20
20
|
ia-book-actions {
|
|
21
21
|
--white: #fff;
|
|
@@ -72,6 +72,10 @@
|
|
|
72
72
|
margin: 2px;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
fieldset {
|
|
76
|
+
display: inline-grid;
|
|
77
|
+
}
|
|
78
|
+
|
|
75
79
|
body.modal-manager-open {
|
|
76
80
|
overflow: hidden;
|
|
77
81
|
}
|
|
@@ -94,15 +98,17 @@
|
|
|
94
98
|
canBrowseAndBorrow,
|
|
95
99
|
} from '../src/assets/data/lending-get-status-service.js';
|
|
96
100
|
import { ModalConfig } from '@internetarchive/modal-manager';
|
|
101
|
+
import { LocalCache } from '@internetarchive/local-cache';
|
|
102
|
+
|
|
103
|
+
const localCache = new LocalCache({
|
|
104
|
+
namespace: 'loanRenew',
|
|
105
|
+
defaultTTL: 1 * 60, // 1 minute
|
|
106
|
+
});
|
|
97
107
|
|
|
98
108
|
const userid = '@neeraj-archive';
|
|
99
109
|
const identifier = 'naturalhistoryof00unse_4111';
|
|
100
110
|
let bwbPurchaseUrl = 'https://www.betterworldbooks.com/product/detail/cambridge-ancient-hist-v04-0521044863';
|
|
101
111
|
|
|
102
|
-
let iaBookActions = document.querySelector('ia-book-actions');
|
|
103
|
-
|
|
104
|
-
// for debugging
|
|
105
|
-
window.iaBookActions = iaBookActions;
|
|
106
112
|
|
|
107
113
|
const modalConfig = new ModalConfig();
|
|
108
114
|
modalConfig.headerColor = '#d9534f';
|
|
@@ -112,6 +118,8 @@
|
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
// set defaultLendingStatus for unavailable (without borrowables) book
|
|
121
|
+
let iaBookActions = document.querySelector('ia-book-actions');
|
|
122
|
+
|
|
115
123
|
iaBookActions.userid = userid;
|
|
116
124
|
iaBookActions.identifier = identifier;
|
|
117
125
|
iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
|
|
@@ -119,10 +127,18 @@
|
|
|
119
127
|
iaBookActions.bwbPurchaseUrl = '';
|
|
120
128
|
iaBookActions.modalConfig = modalConfig;
|
|
121
129
|
iaBookActions.lendingBarPostInit = lendingBarPostInit;
|
|
122
|
-
iaBookActions.tokenDelay =
|
|
130
|
+
iaBookActions.tokenDelay = 2; // 2 seconds
|
|
123
131
|
iaBookActions.returnUrl = 'https://openlibrary.org';
|
|
132
|
+
iaBookActions.localCache = localCache;
|
|
133
|
+
|
|
134
|
+
let loanTotalTime2Min = { loanTotalTime: 20, loanRenewAtLast: 15, pageChangedInLast: 15 };
|
|
135
|
+
let loanTotalTime5Min = { loanTotalTime: 300, loanRenewAtLast: 180, pageChangedInLast: 15 };
|
|
136
|
+
let loanTotalTime1Hour = { loanTotalTime: 3600, loanRenewAtLast: 600, pageChangedInLast: 900 };
|
|
137
|
+
|
|
138
|
+
iaBookActions.loanRenewTimeConfig = loanTotalTime2Min;
|
|
124
139
|
|
|
125
140
|
let lendingStatus1 = iaBookActions.lendingStatus;
|
|
141
|
+
let secondsLeftOnLoan = iaBookActions.loanRenewTimeConfig.loanTotalTime;
|
|
126
142
|
|
|
127
143
|
document.querySelectorAll('.titleBar input[type=checkbox]').forEach((item) => {
|
|
128
144
|
item.addEventListener('click', (e) => {
|
|
@@ -187,12 +203,24 @@
|
|
|
187
203
|
});
|
|
188
204
|
|
|
189
205
|
document.querySelectorAll('.availableToBrowse input[type=radio]').forEach((item) => {
|
|
190
|
-
item.addEventListener('click', (e) => {
|
|
206
|
+
item.addEventListener('click', async (e) => {
|
|
191
207
|
if (e.target.value === 'user_has_browsed') {
|
|
192
208
|
lendingStatus1.user_has_browsed = true;
|
|
193
209
|
lendingStatus1.available_to_browse = false;
|
|
194
|
-
lendingStatus1.secondsLeftOnLoan =
|
|
210
|
+
lendingStatus1.secondsLeftOnLoan = secondsLeftOnLoan;
|
|
195
211
|
lendingStatus1.browsingExpired = false;
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
// set a value
|
|
215
|
+
await localCache.set({
|
|
216
|
+
key: `${identifier}-loanTime`,
|
|
217
|
+
value: new Date(), // current time
|
|
218
|
+
ttl: Number(iaBookActions.loanRenewTimeConfig.loanTotalTime),
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
await localCache.delete(`${identifier}-pageChangedTime`);
|
|
222
|
+
} catch (error) {}
|
|
223
|
+
|
|
196
224
|
} else if(e.target.value === 'browsingExpired') {
|
|
197
225
|
lendingStatus1.user_has_browsed = true;
|
|
198
226
|
lendingStatus1.available_to_browse = false;
|
|
@@ -203,8 +231,11 @@
|
|
|
203
231
|
lendingStatus1.user_has_browsed = false;
|
|
204
232
|
}
|
|
205
233
|
|
|
206
|
-
|
|
207
|
-
|
|
234
|
+
// wait for a while
|
|
235
|
+
setTimeout(() => {
|
|
236
|
+
let lending = {...defaultLendingStatus, ...lendingStatus1};
|
|
237
|
+
iaBookActions.lendingStatus = lending;
|
|
238
|
+
}, 10);
|
|
208
239
|
});
|
|
209
240
|
});
|
|
210
241
|
|
|
@@ -253,6 +284,17 @@
|
|
|
253
284
|
iaBookActions.bwbPurchaseUrl = bwbPurchaseUrl;
|
|
254
285
|
})
|
|
255
286
|
});
|
|
287
|
+
|
|
288
|
+
document.querySelector('.pageChangedEvent').addEventListener('click', () => {
|
|
289
|
+
// dispatch event to say book page has flipped
|
|
290
|
+
document.querySelector('ia-book-actions').dispatchEvent(
|
|
291
|
+
new CustomEvent('BookReader:userAction', {
|
|
292
|
+
detail: {},
|
|
293
|
+
bubbles: true,
|
|
294
|
+
composed: true,
|
|
295
|
+
})
|
|
296
|
+
);
|
|
297
|
+
})
|
|
256
298
|
</script>
|
|
257
299
|
|
|
258
300
|
<div>
|
|
@@ -263,6 +305,9 @@
|
|
|
263
305
|
<td class="titleBar">
|
|
264
306
|
<label><input type="checkbox" name="title" value="title" />Title Bar</label>
|
|
265
307
|
</td>
|
|
308
|
+
<td>
|
|
309
|
+
<button class="pageChangedEvent">Page Change Event</button>
|
|
310
|
+
</td>
|
|
266
311
|
</tr>
|
|
267
312
|
</table>
|
|
268
313
|
</fieldset>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@internetarchive/ia-book-actions",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Bookreader actions for borrowable book",
|
|
5
5
|
"author": "Internet Archive",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@internetarchive/icon-info": "^1.2.6",
|
|
22
|
-
"@internetarchive/local-cache": "^0.2.
|
|
23
|
-
"@internetarchive/modal-manager": "^0.2.
|
|
22
|
+
"@internetarchive/local-cache": "^0.2.1",
|
|
23
|
+
"@internetarchive/modal-manager": "^0.2.8",
|
|
24
24
|
"@internetarchive/shared-resize-observer": "^0.2.0",
|
|
25
|
-
"
|
|
25
|
+
"@internetarchive/toast-manager": "0.1.0",
|
|
26
|
+
"lit": "^2.5.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"@open-wc/eslint-config": "^4.2.0",
|
|
@@ -12,6 +12,7 @@ export default css`
|
|
|
12
12
|
}
|
|
13
13
|
.actiongroup {
|
|
14
14
|
display: flex;
|
|
15
|
+
margin-right: 10px;
|
|
15
16
|
}
|
|
16
17
|
.action-buttons {
|
|
17
18
|
display: inline-flex;
|
|
@@ -33,12 +34,12 @@ export default css`
|
|
|
33
34
|
}
|
|
34
35
|
.primary {
|
|
35
36
|
background-color: ${whiteColor};
|
|
37
|
+
margin-right: 4px;
|
|
36
38
|
}
|
|
37
39
|
.primary,
|
|
38
40
|
.secondary {
|
|
39
41
|
position: relative;
|
|
40
42
|
border-radius: 5px;
|
|
41
|
-
margin: 0 3px;
|
|
42
43
|
}
|
|
43
44
|
.primary .initial {
|
|
44
45
|
border-radius: 4px 0 0 4px;
|
|
@@ -9,6 +9,10 @@ import CollapsibleActionGroupStyle from '../assets/styles/collapsible-action-gro
|
|
|
9
9
|
|
|
10
10
|
import { tabletContainerWidth } from '../core/config/constants.js';
|
|
11
11
|
import { purchaseIcon } from '../assets/data/purchase.js';
|
|
12
|
+
import {
|
|
13
|
+
analyticsCategories,
|
|
14
|
+
analyticsActions,
|
|
15
|
+
} from '../core/config/analytics-event-and-category.js';
|
|
12
16
|
import {
|
|
13
17
|
dropdownOpened,
|
|
14
18
|
dropdownClosed,
|
|
@@ -28,6 +32,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
28
32
|
dropdownArrow: { type: String },
|
|
29
33
|
disabled: { type: Boolean },
|
|
30
34
|
returnUrl: { type: String },
|
|
35
|
+
renewNow: { type: Boolean },
|
|
31
36
|
};
|
|
32
37
|
}
|
|
33
38
|
|
|
@@ -47,6 +52,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
47
52
|
this.loaderIcon = 'https://archive.org/upload/images/tree/loading.gif';
|
|
48
53
|
this.disabled = false;
|
|
49
54
|
this.returnUrl = '';
|
|
55
|
+
this.renewNow = false;
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
updated(changed) {
|
|
@@ -56,6 +62,27 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
56
62
|
) {
|
|
57
63
|
this.resetActions();
|
|
58
64
|
}
|
|
65
|
+
|
|
66
|
+
if (changed.has('renewNow') && this.renewNow === true) {
|
|
67
|
+
this.dispatchLoanRenewEvent();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// dispatch this event to loan renew handler
|
|
72
|
+
dispatchLoanRenewEvent() {
|
|
73
|
+
const { category, action } = {
|
|
74
|
+
category: analyticsCategories.browse,
|
|
75
|
+
action: analyticsActions.browseLoanRenew,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// listen in action-handler.js to execute ajax call on petabox.
|
|
79
|
+
this.dispatchEvent(
|
|
80
|
+
new CustomEvent('loanRenew', {
|
|
81
|
+
detail: {
|
|
82
|
+
event: { category, action },
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
);
|
|
59
86
|
}
|
|
60
87
|
|
|
61
88
|
/**
|
|
@@ -43,21 +43,12 @@ export class InfoIcon extends LitElement {
|
|
|
43
43
|
vertical-align: middle;
|
|
44
44
|
--iconFillColor: white;
|
|
45
45
|
}
|
|
46
|
-
.more-info-icon {
|
|
47
|
-
margin-left: 10px;
|
|
48
|
-
}
|
|
49
46
|
.more-info-icon img {
|
|
50
47
|
width: 24px;
|
|
51
48
|
height: 24px;
|
|
52
49
|
vertical-align: middle;
|
|
53
50
|
background: white;
|
|
54
51
|
}
|
|
55
|
-
.more-info-icon.mobile {
|
|
56
|
-
position: absolute;
|
|
57
|
-
top: 4px;
|
|
58
|
-
right: 10px;
|
|
59
|
-
margin-top: 15px;
|
|
60
|
-
}
|
|
61
52
|
.hidden {
|
|
62
53
|
display: none;
|
|
63
54
|
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { html, css, LitElement } from 'lit';
|
|
2
|
+
import { sentryLogs } from '../core/config/sentry-events.js';
|
|
3
|
+
|
|
4
|
+
export default class TimerCountdown extends LitElement {
|
|
5
|
+
static get properties() {
|
|
6
|
+
return {
|
|
7
|
+
secondsLeftOnLoan: { type: Number }, // in seconds
|
|
8
|
+
loanTotalTime: { type: Number }, // in seconds
|
|
9
|
+
loanRenewAtLast: { type: Number }, // in seconds
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* seconds left in current loan
|
|
18
|
+
* @type {number}
|
|
19
|
+
*/
|
|
20
|
+
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
|
+
* setInterval executed interval
|
|
36
|
+
* @type {number}
|
|
37
|
+
*/
|
|
38
|
+
this.timerInterval = undefined;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* delay seconds in setInterval function
|
|
42
|
+
* @type {number}
|
|
43
|
+
*/
|
|
44
|
+
this.timerExecutionSeconds = 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
disconnectedCallback() {
|
|
48
|
+
clearInterval(this.timerInterval);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
updated(changed) {
|
|
52
|
+
if (changed.has('secondsLeftOnLoan') && this.secondsLeftOnLoan > 0) {
|
|
53
|
+
clearInterval(this.timerInterval);
|
|
54
|
+
this.timerCountdown();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
timerCountdown() {
|
|
59
|
+
// - let just execute setInterval in every 1 minute
|
|
60
|
+
this.timerExecutionSeconds = 60;
|
|
61
|
+
|
|
62
|
+
this.timerInterval = setInterval(() => {
|
|
63
|
+
this.secondsLeftOnLoan -= this.timerExecutionSeconds;
|
|
64
|
+
const secondsLeft = Math.round(this.secondsLeftOnLoan);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* execute from last 10th minute to 0th minute
|
|
68
|
+
* - 10th - to check if user has viewed
|
|
69
|
+
* - till 0th - to show warning msg with remaining time to auto expired
|
|
70
|
+
* @see IABookActions::bindLoanRenewEvents
|
|
71
|
+
*/
|
|
72
|
+
if (secondsLeft <= this.loanRenewAtLast) {
|
|
73
|
+
this.dispatchEvent(
|
|
74
|
+
new CustomEvent('IABookActions:loanRenew', {
|
|
75
|
+
detail: {
|
|
76
|
+
hasPageChanged: false,
|
|
77
|
+
secondsLeft,
|
|
78
|
+
},
|
|
79
|
+
bubbles: true,
|
|
80
|
+
composed: true,
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// clear interval
|
|
86
|
+
if (secondsLeft <= 60) {
|
|
87
|
+
clearInterval(this.timerInterval);
|
|
88
|
+
window?.Sentry?.captureMessage(sentryLogs.clearOneHourTimer);
|
|
89
|
+
}
|
|
90
|
+
}, this.timerExecutionSeconds * 1000);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* get remaining time with timeunit
|
|
95
|
+
*
|
|
96
|
+
* @memberof TimerCountdown
|
|
97
|
+
* @return string
|
|
98
|
+
*/
|
|
99
|
+
get remainingTime() {
|
|
100
|
+
const unitOfTime = 'minute';
|
|
101
|
+
let timeLeft = Math.round(this.secondsLeftOnLoan);
|
|
102
|
+
|
|
103
|
+
// convert time from second to minute
|
|
104
|
+
timeLeft = Math.ceil(timeLeft / 60);
|
|
105
|
+
|
|
106
|
+
return timeLeft !== 1
|
|
107
|
+
? `${timeLeft} ${unitOfTime}s`
|
|
108
|
+
: `${timeLeft} ${unitOfTime}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
render() {
|
|
112
|
+
return html`
|
|
113
|
+
<svg
|
|
114
|
+
width="16"
|
|
115
|
+
height="16"
|
|
116
|
+
viewBox="0 0 100 100"
|
|
117
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
118
|
+
>
|
|
119
|
+
<circle class="circle" cx="50" cy="50" r="50" />
|
|
120
|
+
</svg>
|
|
121
|
+
<span class="sr-only">${this.remainingTime}</span>
|
|
122
|
+
<span>${this.remainingTime}</span>
|
|
123
|
+
`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static get styles() {
|
|
127
|
+
const white = css`var(--white, #fff)`;
|
|
128
|
+
const timerSecondsLeft = css`var(--secondsLeftOnLoan, 6000s)`; //
|
|
129
|
+
const timerStrokeLeft = css`var(--strokeLeftOnLoan, 315)`;
|
|
130
|
+
|
|
131
|
+
return css`
|
|
132
|
+
:host {
|
|
133
|
+
right: 5px;
|
|
134
|
+
position: absolute;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@keyframes circletimer {
|
|
138
|
+
0% {
|
|
139
|
+
stroke-dashoffset: ${timerStrokeLeft};
|
|
140
|
+
stroke-dasharray: 315;
|
|
141
|
+
}
|
|
142
|
+
100% {
|
|
143
|
+
stroke-dashoffset: 0;
|
|
144
|
+
stroke-dasharray: 315;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
svg {
|
|
149
|
+
background-color: ${white};
|
|
150
|
+
border-radius: 50px;
|
|
151
|
+
border: 2px solid ${white};
|
|
152
|
+
transform: rotateZ(-90deg);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
svg .circle {
|
|
156
|
+
stroke: #000;
|
|
157
|
+
stroke-width: 100px;
|
|
158
|
+
fill: ${white};
|
|
159
|
+
stroke-dashoffset: 315;
|
|
160
|
+
stroke-dasharray: 0;
|
|
161
|
+
animation: ${timerSecondsLeft} circletimer linear;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.sr-only {
|
|
165
|
+
position: absolute;
|
|
166
|
+
left: -9999px;
|
|
167
|
+
width: 1px;
|
|
168
|
+
height: 1px;
|
|
169
|
+
margin: 0;
|
|
170
|
+
padding: 0;
|
|
171
|
+
border: none;
|
|
172
|
+
overflow: hidden;
|
|
173
|
+
}
|
|
174
|
+
`;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
window.customElements.define('timer-countdown', TimerCountdown);
|
|
@@ -13,6 +13,7 @@ export const analyticsCategories = {
|
|
|
13
13
|
export const analyticsActions = {
|
|
14
14
|
browse: 'Borrow-1Hour',
|
|
15
15
|
browseAgain: 'Borrow-Again',
|
|
16
|
+
browseLoanRenew: 'Borrow-Loan-Renew',
|
|
16
17
|
borrow: 'Borrow-14Days',
|
|
17
18
|
waitlistJoin: 'JoinWaitlist',
|
|
18
19
|
waitlistLeave: 'LeaveWaitlist',
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sentry logs/messages we send for different actions....
|
|
3
|
+
*/
|
|
4
|
+
export const sentryLogs = {
|
|
5
|
+
disconnectedCallback: 'IABookActions:disconnectedCallback',
|
|
6
|
+
bookHasRenewed:
|
|
7
|
+
'IABookActions:handleLoanAutoRenewed - book has renewed for next one hour',
|
|
8
|
+
browseHasExpired:
|
|
9
|
+
'IABookActions:browseHasExpired - one-hour loan has been expired',
|
|
10
|
+
bookWasExpired:
|
|
11
|
+
'IABookActions:setupLendingToolbarActions - book was expired at intial, no tokenPoller',
|
|
12
|
+
clearTokenPoller:
|
|
13
|
+
'IABookActions:startLoanTokenPoller - clearing token poller interval',
|
|
14
|
+
clearOneHourTimer:
|
|
15
|
+
'IABookActions:timerCountdown - one-hour timer interval cleared',
|
|
16
|
+
bookAccessed: 'IABookActions:bookAccessed',
|
|
17
|
+
handleLoanTokenPoller: 'IABookActions:handleLoanTokenPoller',
|
|
18
|
+
setConsecutiveLoanCounts: 'IABookActions:setConsecutiveLoanCounts',
|
|
19
|
+
actionsHandlerService: 'IABookActions:actionsHandlerService',
|
|
20
|
+
};
|
|
@@ -36,7 +36,7 @@ export default class ActionsConfig {
|
|
|
36
36
|
firstBrowseConfig() {
|
|
37
37
|
return {
|
|
38
38
|
id: 'browseBook',
|
|
39
|
-
text: 'Borrow
|
|
39
|
+
text: 'Borrow',
|
|
40
40
|
className: 'primary',
|
|
41
41
|
analyticsEvent: {
|
|
42
42
|
category: this.analyticsCategories.preview,
|
|
@@ -48,7 +48,7 @@ export default class ActionsConfig {
|
|
|
48
48
|
browseAgainConfig() {
|
|
49
49
|
return {
|
|
50
50
|
id: 'browseBookAgain',
|
|
51
|
-
text: 'Borrow
|
|
51
|
+
text: 'Borrow',
|
|
52
52
|
className: 'primary',
|
|
53
53
|
analyticsEvent: {
|
|
54
54
|
category: this.analyticsCategories.browse,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
|
+
import { sentryLogs } from '../../config/sentry-events.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Helper to call loan service
|
|
@@ -64,7 +65,9 @@ export default async function ActionsHandlerService(options) {
|
|
|
64
65
|
option?.error(data);
|
|
65
66
|
}
|
|
66
67
|
});
|
|
67
|
-
} catch (
|
|
68
|
-
window?.Sentry?.captureException(
|
|
68
|
+
} catch (error) {
|
|
69
|
+
window?.Sentry?.captureException(
|
|
70
|
+
`${sentryLogs.actionsHandlerService} - Error: ${error}`
|
|
71
|
+
);
|
|
69
72
|
}
|
|
70
73
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
2
|
|
|
3
3
|
import { URLHelper } from '../../config/url-helper.js';
|
|
4
|
+
import { sentryLogs } from '../../config/sentry-events.js';
|
|
5
|
+
|
|
4
6
|
import ActionsHandlerService from './actions-handler-service.js';
|
|
5
7
|
import * as Cookies from '../doc-cookies.js';
|
|
6
8
|
|
|
@@ -15,10 +17,14 @@ import * as Cookies from '../doc-cookies.js';
|
|
|
15
17
|
export default class ActionsHandler extends LitElement {
|
|
16
18
|
constructor() {
|
|
17
19
|
super();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* wait untill borrow is complete, then refresh the page
|
|
23
|
+
* @type {number}
|
|
24
|
+
*/
|
|
25
|
+
this.waitUntillBorrowComplete = 6; // in seconds
|
|
26
|
+
|
|
20
27
|
this.bindEvents();
|
|
21
|
-
this.returnUrl = '';
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
sendEvent(eventCategory, eventAction) {
|
|
@@ -44,6 +50,12 @@ export default class ActionsHandler extends LitElement {
|
|
|
44
50
|
this.sendEvent(category, action);
|
|
45
51
|
});
|
|
46
52
|
|
|
53
|
+
this.addEventListener('loanRenew', ({ detail }) => {
|
|
54
|
+
this.handleLoanRenew();
|
|
55
|
+
const { category, action } = detail.event;
|
|
56
|
+
this.sendEvent(category, action);
|
|
57
|
+
});
|
|
58
|
+
|
|
47
59
|
this.addEventListener('returnNow', ({ detail }) => {
|
|
48
60
|
this.handleReturnIt();
|
|
49
61
|
const { category, action } = detail.event;
|
|
@@ -103,6 +115,7 @@ export default class ActionsHandler extends LitElement {
|
|
|
103
115
|
action,
|
|
104
116
|
identifier: this.identifier,
|
|
105
117
|
success: () => {
|
|
118
|
+
this.setBrowseTimeSession();
|
|
106
119
|
this.handleReadItNow();
|
|
107
120
|
},
|
|
108
121
|
error: data => {
|
|
@@ -111,6 +124,26 @@ export default class ActionsHandler extends LitElement {
|
|
|
111
124
|
});
|
|
112
125
|
}
|
|
113
126
|
|
|
127
|
+
handleLoanRenew() {
|
|
128
|
+
const action = 'renew_loan';
|
|
129
|
+
|
|
130
|
+
ActionsHandlerService({
|
|
131
|
+
action,
|
|
132
|
+
identifier: this.identifier,
|
|
133
|
+
success: data => {
|
|
134
|
+
this.setBrowseTimeSession();
|
|
135
|
+
this.dispatchEvent(
|
|
136
|
+
new CustomEvent('loanAutoRenewed', {
|
|
137
|
+
detail: { action, data },
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
},
|
|
141
|
+
error: data => {
|
|
142
|
+
this.dispatchActionError(action, data);
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
114
147
|
handleReturnIt() {
|
|
115
148
|
const action = 'return_loan';
|
|
116
149
|
this.dispatchToggleActionGroup();
|
|
@@ -235,7 +268,7 @@ export default class ActionsHandler extends LitElement {
|
|
|
235
268
|
// redirection on details page after 5 seconds because borrowing book takes time to create item creation.
|
|
236
269
|
setTimeout(() => {
|
|
237
270
|
URLHelper.goToUrl(redirectTo, true);
|
|
238
|
-
}, this.
|
|
271
|
+
}, this.waitUntillBorrowComplete * 1000);
|
|
239
272
|
}
|
|
240
273
|
|
|
241
274
|
// save consecutive loan count for borrow
|
|
@@ -256,11 +289,36 @@ export default class ActionsHandler extends LitElement {
|
|
|
256
289
|
// set new value
|
|
257
290
|
Cookies.setItem(storageKey, newCount, date, '/');
|
|
258
291
|
} catch (error) {
|
|
259
|
-
window?.Sentry?.captureException(
|
|
292
|
+
window?.Sentry?.captureException(
|
|
293
|
+
`${sentryLogs.setConsecutiveLoanCounts} - Error: ${error}`
|
|
294
|
+
);
|
|
260
295
|
this.sendEvent('Cookies-Error-Actions', error);
|
|
261
296
|
}
|
|
262
297
|
}
|
|
263
298
|
|
|
299
|
+
/**
|
|
300
|
+
* set browse time in indexedDB
|
|
301
|
+
*/
|
|
302
|
+
async setBrowseTimeSession() {
|
|
303
|
+
try {
|
|
304
|
+
const expireDate = new Date(
|
|
305
|
+
new Date().getTime() + this.loanTotalTime * 1000
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
// set a value
|
|
309
|
+
await this.localCache.set({
|
|
310
|
+
key: `${this.identifier}-loanTime`,
|
|
311
|
+
value: expireDate,
|
|
312
|
+
ttl: Number(this.loanTotalTime),
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// delete pageChangedTime when book is auto renew at nth minute
|
|
316
|
+
await this.localCache.delete(`${this.identifier}-pageChangedTime`);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
console.log(error);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
264
322
|
deleteLoanCookies() {
|
|
265
323
|
const date = new Date();
|
|
266
324
|
date.setTime(date.getTime() - 24 * 60 * 60 * 1000); // one day ago
|
|
@@ -19,7 +19,7 @@ import ActionsConfig from './actions-config.js';
|
|
|
19
19
|
*
|
|
20
20
|
* Response of this class contain an object as follows:-
|
|
21
21
|
* {
|
|
22
|
-
* primaryTitle: '
|
|
22
|
+
* primaryTitle: '',
|
|
23
23
|
* primaryActions: [this.actionsConfig.returnBookConfig()],
|
|
24
24
|
* primaryColor: 'primary',
|
|
25
25
|
* secondaryActions: [this.actionsConfig.purchaseConfig()],
|
|
@@ -40,7 +40,7 @@ import ActionsConfig from './actions-config.js';
|
|
|
40
40
|
* @enum {string}
|
|
41
41
|
*/
|
|
42
42
|
export const bookTitles = {
|
|
43
|
-
available_1hr: '
|
|
43
|
+
available_1hr: '',
|
|
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: '
|
|
52
|
+
session_expired: '',
|
|
53
53
|
unavailable: 'This book is not available at this time.',
|
|
54
54
|
};
|
|
55
55
|
|
|
@@ -98,7 +98,7 @@ export class GetLendingActions {
|
|
|
98
98
|
let isBrowsing =
|
|
99
99
|
lendingStatus.user_has_browsed && !lendingStatus.browsingExpired;
|
|
100
100
|
if (isBrowsing) {
|
|
101
|
-
primaryTitleText =
|
|
101
|
+
primaryTitleText = '';
|
|
102
102
|
} else {
|
|
103
103
|
primaryTitleText = `Your loan of this book has ${lendingStatus.daysLeftOnLoan} days left.`;
|
|
104
104
|
}
|
|
@@ -251,13 +251,6 @@ export class GetLendingActions {
|
|
|
251
251
|
borrow1HrAction() {
|
|
252
252
|
const lendingStatus = this.lendingStatus || {};
|
|
253
253
|
|
|
254
|
-
const possibleTitles = {
|
|
255
|
-
one_hour: 'Renewable every hour, pending availability.',
|
|
256
|
-
session_tryagain:
|
|
257
|
-
'Another patron is using this book. Please check back later.',
|
|
258
|
-
session_expired: 'Your loan has expired.',
|
|
259
|
-
};
|
|
260
|
-
|
|
261
254
|
// assess borrowable state
|
|
262
255
|
const browsingHasExpired =
|
|
263
256
|
!lendingStatus.available_to_browse && lendingStatus.browsingExpired;
|
|
@@ -364,6 +357,8 @@ export class GetLendingActions {
|
|
|
364
357
|
}
|
|
365
358
|
|
|
366
359
|
/**
|
|
360
|
+
* @deprecated
|
|
361
|
+
*
|
|
367
362
|
* Builds the countdown toolbar title.
|
|
368
363
|
*
|
|
369
364
|
* @return string innerHTML for the dialogOpts title attribute
|