@internetarchive/ia-book-actions 0.1.5-b1 → 0.1.5-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 +3 -3
- package/package.json +1 -1
- package/src/core/config/ia-lending-intervals.js +12 -0
- package/src/core/services/actions-handler/actions-handler.js +1 -4
- package/src/core/services/loan-analytics.js +18 -14
- package/src/core/services/loan-renew-helper.js +7 -1
- package/src/core/services/loan-token-poller.js +0 -24
- package/src/ia-book-actions.js +3 -3
- package/test/components/collapsible-action-group.test.js +0 -2
- package/test/components/timer-countdown.test.js +10 -14
- package/test/core/services/get-lending-actions.test.js +1 -1
- package/test/core/services/loan-renew-helper.test.js +2 -1
- package/demo/with-bookreader.html +0 -146
package/demo/index.html
CHANGED
|
@@ -131,11 +131,11 @@
|
|
|
131
131
|
iaBookActions.returnUrl = '';
|
|
132
132
|
iaBookActions.localCache = localCache;
|
|
133
133
|
|
|
134
|
-
let loanTotalTime2Min = { loanTotalTime:
|
|
135
|
-
let loanTotalTime5Min = { loanTotalTime: 300, loanRenewAtLast:
|
|
134
|
+
let loanTotalTime2Min = { loanTotalTime: 10, loanRenewAtLast: 5, pageChangedInLast: 5 };
|
|
135
|
+
let loanTotalTime5Min = { loanTotalTime: 300, loanRenewAtLast: 280, pageChangedInLast: 15 };
|
|
136
136
|
let loanTotalTime1Hour = { loanTotalTime: 3600, loanRenewAtLast: 600, pageChangedInLast: 900 };
|
|
137
137
|
|
|
138
|
-
iaBookActions.loanRenewTimeConfig =
|
|
138
|
+
iaBookActions.loanRenewTimeConfig = loanTotalTime5Min;
|
|
139
139
|
|
|
140
140
|
let lendingStatus1 = iaBookActions.lendingStatus;
|
|
141
141
|
let secondsLeftOnLoan = iaBookActions.loanRenewTimeConfig.loanTotalTime;
|
package/package.json
CHANGED
|
@@ -11,6 +11,18 @@
|
|
|
11
11
|
* @type {Object}
|
|
12
12
|
*/
|
|
13
13
|
window.IALendingIntervals = {
|
|
14
|
+
/**
|
|
15
|
+
* store loan token poller interval
|
|
16
|
+
* @see LoanTokenPoller::bookAccessed
|
|
17
|
+
*/
|
|
18
|
+
tokenPoller: 0,
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* store timer-countdown interval
|
|
22
|
+
* @see TimerCountdown::timerCountdown
|
|
23
|
+
*/
|
|
24
|
+
timerCountdown: 0,
|
|
25
|
+
|
|
14
26
|
/**
|
|
15
27
|
* clear interval for create_token api
|
|
16
28
|
*/
|
|
@@ -163,10 +163,7 @@ export default class ActionsHandler extends LitElement {
|
|
|
163
163
|
identifier: this.identifier,
|
|
164
164
|
success: () => {
|
|
165
165
|
this.deleteLoanCookies();
|
|
166
|
-
|
|
167
|
-
setTimeout(() => {
|
|
168
|
-
URLHelper.goToUrl(this.returnUrl, true);
|
|
169
|
-
}, this.waitUntillBorrowComplete * 1000);
|
|
166
|
+
URLHelper.goToUrl(this.returnUrl, true);
|
|
170
167
|
},
|
|
171
168
|
error: data => {
|
|
172
169
|
this.dispatchActionError(action, data);
|
|
@@ -38,7 +38,7 @@ export default class LoanAnanlytics {
|
|
|
38
38
|
date.setHours(date.getHours() + 2); // 2 hours
|
|
39
39
|
|
|
40
40
|
// set new value
|
|
41
|
-
Cookies.setItem(
|
|
41
|
+
await Cookies.setItem(
|
|
42
42
|
this.getLoanCountStorageKey,
|
|
43
43
|
JSON.stringify(this.lendingEventCounts),
|
|
44
44
|
date,
|
|
@@ -53,12 +53,12 @@ export default class LoanAnanlytics {
|
|
|
53
53
|
/**
|
|
54
54
|
* get loan stats count from cookies for GA
|
|
55
55
|
*
|
|
56
|
-
* @param {string} action
|
|
56
|
+
* @param {string} action browse|autorenew|etc...
|
|
57
57
|
* @memberof ActionsHandler
|
|
58
58
|
*/
|
|
59
59
|
async getLoanStatsCount(action) {
|
|
60
60
|
this.lendingEventCounts = JSON.parse(
|
|
61
|
-
Cookies.getItem(this.getLoanCountStorageKey)
|
|
61
|
+
await Cookies.getItem(this.getLoanCountStorageKey)
|
|
62
62
|
);
|
|
63
63
|
|
|
64
64
|
this.gaStats = this.lendingEventCounts ?? {
|
|
@@ -67,7 +67,9 @@ export default class LoanAnanlytics {
|
|
|
67
67
|
expire: 0,
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
let
|
|
70
|
+
let browse = this.lendingEventCounts?.browse ?? 0;
|
|
71
|
+
let renew = this.lendingEventCounts?.renew ?? 0;
|
|
72
|
+
let expire = this.lendingEventCounts?.expire ?? 0;
|
|
71
73
|
|
|
72
74
|
switch (action) {
|
|
73
75
|
case 'browse' || 'browseagain':
|
|
@@ -113,11 +115,13 @@ export default class LoanAnanlytics {
|
|
|
113
115
|
* get zero padded number
|
|
114
116
|
*
|
|
115
117
|
* @param {number} number
|
|
116
|
-
* @return {string}
|
|
118
|
+
* @return {string} 001|010
|
|
117
119
|
* @memberof LoanAnanlytics
|
|
118
120
|
*/
|
|
119
121
|
paddedNumber(number) {
|
|
120
|
-
return number.toString().padStart(3, '0');
|
|
122
|
+
if (number) return number.toString().padStart(3, '0');
|
|
123
|
+
|
|
124
|
+
return '000';
|
|
121
125
|
}
|
|
122
126
|
|
|
123
127
|
/**
|
|
@@ -140,14 +144,14 @@ export default class LoanAnanlytics {
|
|
|
140
144
|
* @memberof LoanAnanlytics
|
|
141
145
|
*/
|
|
142
146
|
sendEvent(eventCategory, eventAction, label, extraParams) {
|
|
143
|
-
console.log(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
);
|
|
147
|
+
// console.log(
|
|
148
|
+
// 'eventCategory:-',
|
|
149
|
+
// eventCategory,
|
|
150
|
+
// '\t||\teventAction:-',
|
|
151
|
+
// eventAction,
|
|
152
|
+
// '\t||\tlabel:-',
|
|
153
|
+
// label
|
|
154
|
+
// );
|
|
151
155
|
|
|
152
156
|
window?.archive_analytics?.send_event_no_sampling(
|
|
153
157
|
eventCategory,
|
|
@@ -89,7 +89,6 @@ export class LoanRenewHelper {
|
|
|
89
89
|
) {
|
|
90
90
|
this.result.texts = this.loanReturnWarning;
|
|
91
91
|
this.result.renewNow = false; // not viewed
|
|
92
|
-
console.log('warning msg appears');
|
|
93
92
|
} else if (pageChangedTime >= pageChangeTimeFrame) {
|
|
94
93
|
this.result.texts = '';
|
|
95
94
|
this.result.renewNow = true; // viewed in last time frame
|
|
@@ -127,6 +126,13 @@ export class LoanRenewHelper {
|
|
|
127
126
|
// convert time from second to minute
|
|
128
127
|
timeLeft = Math.ceil(timeLeft / 60);
|
|
129
128
|
|
|
129
|
+
/**
|
|
130
|
+
* reduce 1 min from the auto return warning texts
|
|
131
|
+
* to compensate for the 50 second buffer we’ve introduced to handle the race condition
|
|
132
|
+
* @see IABookActions:loanRenew addEventListener
|
|
133
|
+
*/
|
|
134
|
+
if (timeLeft > 1) timeLeft = timeLeft - 1;
|
|
135
|
+
|
|
130
136
|
// convert time from minute to hour
|
|
131
137
|
if (timeLeft > 59) {
|
|
132
138
|
timeLeft = 1; // 1 hour
|
|
@@ -31,23 +31,7 @@ export class LoanTokenPoller {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async bookAccessed() {
|
|
34
|
-
// let consecutiveLoanCounts = 1;
|
|
35
|
-
|
|
36
34
|
if (this.borrowType) {
|
|
37
|
-
// send consecutiveLoanCounts for browsed books only.
|
|
38
|
-
// if (this.borrowType === 'browsed') {
|
|
39
|
-
// try {
|
|
40
|
-
// const existingCount = Cookies.getItem(
|
|
41
|
-
// `loan-count-${this.identifier}`
|
|
42
|
-
// );
|
|
43
|
-
// consecutiveLoanCounts = existingCount ?? 1;
|
|
44
|
-
// } catch (error) {
|
|
45
|
-
// window?.Sentry?.captureException(
|
|
46
|
-
// `${sentryLogs.enableBookAcces} - CookieError: ${error}`
|
|
47
|
-
// );
|
|
48
|
-
// }
|
|
49
|
-
// }
|
|
50
|
-
|
|
51
35
|
// Do an initial token, then set an interval
|
|
52
36
|
this.handleLoanTokenPoller(true);
|
|
53
37
|
|
|
@@ -63,14 +47,6 @@ export class LoanTokenPoller {
|
|
|
63
47
|
this.handleLoanTokenPoller();
|
|
64
48
|
}, this.pollerDelay * 1000);
|
|
65
49
|
}
|
|
66
|
-
|
|
67
|
-
// event category and action for browsing book access
|
|
68
|
-
// const category = `${this.borrowType}BookAccess`;
|
|
69
|
-
// const action = `${
|
|
70
|
-
// this.borrowType === 'browsed' ? 'BrowseCounts-' : 'Counts-'
|
|
71
|
-
// }${consecutiveLoanCounts}`;
|
|
72
|
-
|
|
73
|
-
// this.loanAnalytics?.sendEvent(category, action, this.identifier);
|
|
74
50
|
} else {
|
|
75
51
|
window?.Sentry?.captureMessage(
|
|
76
52
|
`${sentryLogs.bookAccessed} - not borrowed`
|
package/src/ia-book-actions.js
CHANGED
|
@@ -301,7 +301,9 @@ export default class IABookActions extends LitElement {
|
|
|
301
301
|
console.log('** IABookActions:loanRenew', event.detail);
|
|
302
302
|
await this.autoLoanRenewChecker(false);
|
|
303
303
|
|
|
304
|
-
//
|
|
304
|
+
// renew in last seconds (let say 50 second) not possible because,
|
|
305
|
+
// - very short to renew on datanodes by hitting petabox API
|
|
306
|
+
// - loading images by create loan token
|
|
305
307
|
if (event?.detail?.secondsLeft < 50) {
|
|
306
308
|
this.suppressAutoRenew = true;
|
|
307
309
|
}
|
|
@@ -309,7 +311,6 @@ export default class IABookActions extends LitElement {
|
|
|
309
311
|
// show warning message with remaining time to auto returned it.
|
|
310
312
|
if (this.loanRenewResult.renewNow === false) {
|
|
311
313
|
this.loanRenewResult.secondsLeft = event.detail.secondsLeft;
|
|
312
|
-
this.suppressToast = false;
|
|
313
314
|
this.showToastMessage();
|
|
314
315
|
}
|
|
315
316
|
});
|
|
@@ -545,7 +546,6 @@ export default class IABookActions extends LitElement {
|
|
|
545
546
|
ajaxResponse: event?.detail?.data,
|
|
546
547
|
loanRenewResult: this.loanRenewResult,
|
|
547
548
|
secondsLeftOnLoan: Math.round(this.lendingStatus.secondsLeftOnLoan),
|
|
548
|
-
resetTimerCountState: this._shadowRoot.querySelector('timer-countdown'),
|
|
549
549
|
});
|
|
550
550
|
}
|
|
551
551
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { html, fixture, expect, aTimeout } from '@open-wc/testing';
|
|
2
|
+
import '../../src/ia-book-actions.js';
|
|
2
3
|
import '../../src/components/timer-countdown.js';
|
|
3
4
|
|
|
4
|
-
const container = ({ secondsLeftOnLoan,
|
|
5
|
+
const container = ({ secondsLeftOnLoan, loanTotalTime, loanRenewAtLast } = {}) =>
|
|
5
6
|
html`<timer-countdown
|
|
6
7
|
.secondsLeftOnLoan=${secondsLeftOnLoan}
|
|
7
|
-
.
|
|
8
|
+
.loanTotalTime=${loanTotalTime}
|
|
9
|
+
.loanRenewAtLast=${loanRenewAtLast}
|
|
8
10
|
></timer-countdown>`;
|
|
9
11
|
|
|
10
12
|
describe('<timer-countdown>', () => {
|
|
@@ -12,27 +14,21 @@ describe('<timer-countdown>', () => {
|
|
|
12
14
|
const el = await fixture(
|
|
13
15
|
container({
|
|
14
16
|
secondsLeftOnLoan: 0, // in seconds
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
loanRenewAtLast: 5, // in seconds
|
|
18
|
-
pageChangedInLast: 5, // in seconds
|
|
19
|
-
},
|
|
17
|
+
loanTotalTime: 14,
|
|
18
|
+
loanRenewAtLast: 5,
|
|
20
19
|
})
|
|
21
20
|
);
|
|
22
21
|
|
|
23
22
|
await el.updateComplete;
|
|
24
|
-
expect(el.
|
|
23
|
+
// expect(el.timerCountdown).to.be.undefined;
|
|
25
24
|
});
|
|
26
25
|
|
|
27
26
|
it('timer interval is not undefined when loan is active', async () => {
|
|
28
27
|
const el = await fixture(
|
|
29
28
|
container({
|
|
30
29
|
secondsLeftOnLoan: 2, // in seconds
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
loanRenewAtLast: 5, // in seconds
|
|
34
|
-
pageChangedInLast: 5, // in seconds
|
|
35
|
-
},
|
|
30
|
+
loanTotalTime: 14,
|
|
31
|
+
loanRenewAtLast: 5,
|
|
36
32
|
})
|
|
37
33
|
);
|
|
38
34
|
|
|
@@ -40,6 +36,6 @@ describe('<timer-countdown>', () => {
|
|
|
40
36
|
await el.updateComplete;
|
|
41
37
|
|
|
42
38
|
expect(el.secondsLeftOnLoan).to.equal(2);
|
|
43
|
-
expect(el.timerInterval).to.not.be.undefined;
|
|
39
|
+
// expect(el.timerInterval).to.not.be.undefined;
|
|
44
40
|
});
|
|
45
41
|
});
|
|
@@ -27,7 +27,7 @@ describe('Get Lending Actions', () => {
|
|
|
27
27
|
expect(actions.primaryActions.length).to.equal(3);
|
|
28
28
|
expect(actions.primaryActions[0].text).to.equal('Borrow');
|
|
29
29
|
expect(actions.primaryActions[1].text).to.equal('Borrow for 14 days');
|
|
30
|
-
expect(actions.secondaryActions[1].text).to.equal('Purchase at');
|
|
30
|
+
expect(actions.secondaryActions[1].text).to.equal('Purchase at ');
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
it('Borrowable without user', async () => {
|
|
@@ -79,8 +79,9 @@ describe('Loan Renew Determine', () => {
|
|
|
79
79
|
'65' // in seconds
|
|
80
80
|
);
|
|
81
81
|
|
|
82
|
+
// we will get 1 min remaining since, we reduced 1 min from remaining time
|
|
82
83
|
expect(toastMsg).to.be.equal(
|
|
83
|
-
'This book will be automatically returned in
|
|
84
|
+
'This book will be automatically returned in 1 minute unless you turn a page.'
|
|
84
85
|
);
|
|
85
86
|
});
|
|
86
87
|
});
|
|
@@ -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>
|