@internetarchive/ia-book-actions 0.0.29-alpha2 → 0.0.29-alpha20
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 +27 -30
- package/package.json +11 -5
- package/src/assets/data/lending-get-status-service.js +1 -1
- package/src/components/collapsible-action-group.js +25 -12
- package/src/components/timer-countdown.js +20 -34
- package/src/core/config/analytics-event-and-category.js +1 -0
- package/src/core/services/actions-handler/actions-handler.js +25 -30
- package/src/core/services/one-hour-loan-renew.js +148 -0
- package/src/ia-book-actions.js +111 -82
- package/src/assets/styles/timer-countdown.js +0 -58
- package/src/components/toast-message.js +0 -60
- package/src/core/services/one-hour-auto-renew.js +0 -148
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;
|
|
@@ -87,6 +87,7 @@
|
|
|
87
87
|
|
|
88
88
|
<script type="module">
|
|
89
89
|
/* eslint-disable */
|
|
90
|
+
|
|
90
91
|
import '../src/ia-book-actions.js';
|
|
91
92
|
import {
|
|
92
93
|
defaultLendingStatus,
|
|
@@ -96,7 +97,7 @@
|
|
|
96
97
|
import { LocalCache } from '@internetarchive/local-cache';
|
|
97
98
|
|
|
98
99
|
const localCache = new LocalCache({
|
|
99
|
-
namespace: '
|
|
100
|
+
namespace: 'loanRenew',
|
|
100
101
|
defaultTTL: 1 * 60, // 1 minute
|
|
101
102
|
});
|
|
102
103
|
|
|
@@ -104,10 +105,6 @@
|
|
|
104
105
|
const identifier = 'naturalhistoryof00unse_4111';
|
|
105
106
|
let bwbPurchaseUrl = 'https://www.betterworldbooks.com/product/detail/cambridge-ancient-hist-v04-0521044863';
|
|
106
107
|
|
|
107
|
-
let iaBookActions = document.querySelector('ia-book-actions');
|
|
108
|
-
|
|
109
|
-
// for debugging
|
|
110
|
-
window.iaBookActions = iaBookActions;
|
|
111
108
|
|
|
112
109
|
const modalConfig = new ModalConfig();
|
|
113
110
|
modalConfig.headerColor = '#d9534f';
|
|
@@ -117,6 +114,8 @@
|
|
|
117
114
|
}
|
|
118
115
|
|
|
119
116
|
// set defaultLendingStatus for unavailable (without borrowables) book
|
|
117
|
+
let iaBookActions = document.querySelector('ia-book-actions');
|
|
118
|
+
|
|
120
119
|
iaBookActions.userid = userid;
|
|
121
120
|
iaBookActions.identifier = identifier;
|
|
122
121
|
iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
|
|
@@ -127,14 +126,14 @@
|
|
|
127
126
|
iaBookActions.tokenDelay = 2000; // 2 seconds
|
|
128
127
|
iaBookActions.returnUrl = 'https://openlibrary.org';
|
|
129
128
|
iaBookActions.localCache = localCache;
|
|
130
|
-
iaBookActions.
|
|
131
|
-
totalTime:
|
|
132
|
-
autoCheckAt:
|
|
133
|
-
|
|
129
|
+
iaBookActions.loanRenewConfig = {
|
|
130
|
+
totalTime: 40, // 60 second = 1 min
|
|
131
|
+
autoCheckAt: 35, // totalTime - 10th minute
|
|
132
|
+
pageChangedInLast: 5, // within last 15 second/minute
|
|
134
133
|
};
|
|
135
134
|
|
|
136
135
|
let lendingStatus1 = iaBookActions.lendingStatus;
|
|
137
|
-
let secondsLeftOnLoan =
|
|
136
|
+
let secondsLeftOnLoan = iaBookActions.loanRenewConfig.totalTime;
|
|
138
137
|
|
|
139
138
|
document.querySelectorAll('.titleBar input[type=checkbox]').forEach((item) => {
|
|
140
139
|
item.addEventListener('click', (e) => {
|
|
@@ -146,21 +145,6 @@
|
|
|
146
145
|
});
|
|
147
146
|
});
|
|
148
147
|
|
|
149
|
-
document.querySelectorAll('.autoRenew input[type=checkbox]').forEach((item) => {
|
|
150
|
-
item.addEventListener('click', (e) => {
|
|
151
|
-
if (e.target.checked) {
|
|
152
|
-
iaBookActions.autoRenew = true;
|
|
153
|
-
iaBookActions.resetTimerCountdown = true;
|
|
154
|
-
lendingStatus1.secondsLeftOnLoan = secondsLeftOnLoan;
|
|
155
|
-
} else {
|
|
156
|
-
iaBookActions.autoRenew = false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
let lending = {...defaultLendingStatus, ...lendingStatus1};
|
|
160
|
-
iaBookActions.lendingStatus = lending;
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
148
|
document.querySelectorAll('.errorEnable input[type=checkbox]').forEach((item) => {
|
|
165
149
|
if (window.location.href.indexOf('?error=true') !== -1) {
|
|
166
150
|
item.checked = true;
|
|
@@ -226,10 +210,10 @@
|
|
|
226
210
|
await localCache.set({
|
|
227
211
|
key: `${identifier}-loanTime`,
|
|
228
212
|
value: new Date(), // current time
|
|
229
|
-
ttl:
|
|
230
|
-
})
|
|
213
|
+
ttl: Number(iaBookActions.loanRenewConfig.totalTime),
|
|
214
|
+
});
|
|
231
215
|
|
|
232
|
-
await localCache.delete(`${identifier}-
|
|
216
|
+
await localCache.delete(`${identifier}-pageChangedTime`);
|
|
233
217
|
} catch (error) {}
|
|
234
218
|
|
|
235
219
|
} else if(e.target.value === 'browsingExpired') {
|
|
@@ -292,6 +276,17 @@
|
|
|
292
276
|
iaBookActions.bwbPurchaseUrl = bwbPurchaseUrl;
|
|
293
277
|
})
|
|
294
278
|
});
|
|
279
|
+
|
|
280
|
+
document.querySelector('.pageChangedEvent').addEventListener('click', () => {
|
|
281
|
+
// dispatch event to say book page has flipped
|
|
282
|
+
document.querySelector('ia-book-actions').dispatchEvent(
|
|
283
|
+
new CustomEvent('BookReader:pageChanged', {
|
|
284
|
+
detail: { isPageChanged: true },
|
|
285
|
+
bubbles: true,
|
|
286
|
+
composed: true,
|
|
287
|
+
})
|
|
288
|
+
);
|
|
289
|
+
})
|
|
295
290
|
</script>
|
|
296
291
|
|
|
297
292
|
<div>
|
|
@@ -302,6 +297,9 @@
|
|
|
302
297
|
<td class="titleBar">
|
|
303
298
|
<label><input type="checkbox" name="title" value="title" />Title Bar</label>
|
|
304
299
|
</td>
|
|
300
|
+
<td>
|
|
301
|
+
<button class="pageChangedEvent">Page Change Event</button>
|
|
302
|
+
</td>
|
|
305
303
|
</tr>
|
|
306
304
|
</table>
|
|
307
305
|
</fieldset>
|
|
@@ -311,7 +309,6 @@
|
|
|
311
309
|
<table class="initial">
|
|
312
310
|
<tr colspan='5'>
|
|
313
311
|
<td class="errorEnable"><label><input type="checkbox" name="errorEnable" value="errorEnable" />Do you want to see error response?</label></td>
|
|
314
|
-
<td class="autoRenew"><label><input type="checkbox" name="autoRenew" value="autoRenew" />Do you want to auto-renew 1 hour</label></td>
|
|
315
312
|
</tr>
|
|
316
313
|
<tr>
|
|
317
314
|
<td class="userState">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@internetarchive/ia-book-actions",
|
|
3
|
-
"version": "0.0.29-
|
|
3
|
+
"version": "0.0.29-alpha20",
|
|
4
4
|
"description": "Bookreader actions for borrowable book",
|
|
5
5
|
"author": "Internet Archive",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"start": "web-dev-server",
|
|
14
|
-
"lint": "eslint --ext .js",
|
|
15
|
-
"format": "eslint --ext .js
|
|
14
|
+
"lint": "eslint --ext .js,.html . --ignore-path .gitignore && prettier \"**/*.js\" --check --ignore-path .gitignore",
|
|
15
|
+
"format": "eslint --ext .js,.html . --fix --ignore-path .gitignore && prettier \"**/*.js\" --write --ignore-path .gitignore",
|
|
16
16
|
"test": "yarn run lint && yarn test:fast",
|
|
17
17
|
"test:fast": "web-test-runner --coverage --playwright --browsers chromium firefox webkit",
|
|
18
18
|
"test:watch": "web-test-runner --watch --playwright --browsers chromium firefox webkit"
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"@internetarchive/local-cache": "^0.2.0",
|
|
23
23
|
"@internetarchive/modal-manager": "^0.2.1",
|
|
24
24
|
"@internetarchive/shared-resize-observer": "^0.2.0",
|
|
25
|
+
"@internetarchive/toast-manager": "0.0.1-alpha5",
|
|
25
26
|
"lit": "^2.2.1"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
@@ -43,6 +44,12 @@
|
|
|
43
44
|
"sinon": "^13.0.2"
|
|
44
45
|
},
|
|
45
46
|
"eslintConfig": {
|
|
47
|
+
"rules": {
|
|
48
|
+
"no-console": "off",
|
|
49
|
+
"no-unused-expressions": "off",
|
|
50
|
+
"class-methods-use-this": "off",
|
|
51
|
+
"lit-a11y/click-events-have-key-events": "off"
|
|
52
|
+
},
|
|
46
53
|
"extends": [
|
|
47
54
|
"@open-wc/eslint-config",
|
|
48
55
|
"eslint-config-prettier"
|
|
@@ -53,8 +60,7 @@
|
|
|
53
60
|
"arrowParens": "avoid"
|
|
54
61
|
},
|
|
55
62
|
"husky": {
|
|
56
|
-
"hooks": {
|
|
57
|
-
}
|
|
63
|
+
"hooks": {}
|
|
58
64
|
},
|
|
59
65
|
"lint-staged": {
|
|
60
66
|
"*.js": [
|
|
@@ -100,7 +100,7 @@ export const canBrowseAndBorrow = {
|
|
|
100
100
|
// userid: "",
|
|
101
101
|
bookUrl: '/details/practicalorganic00plim',
|
|
102
102
|
daysLeftOnLoan: 0,
|
|
103
|
-
isAdmin:
|
|
103
|
+
isAdmin: false,
|
|
104
104
|
isArchiveOrgLending: true,
|
|
105
105
|
isAvailable: false,
|
|
106
106
|
isAvailableForBrowsing: false,
|
|
@@ -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,8 +32,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
28
32
|
dropdownArrow: { type: String },
|
|
29
33
|
disabled: { type: Boolean },
|
|
30
34
|
returnUrl: { type: String },
|
|
31
|
-
|
|
32
|
-
autoRenewTimeConfig: { type: Object },
|
|
35
|
+
renewNow: { type: Boolean },
|
|
33
36
|
};
|
|
34
37
|
}
|
|
35
38
|
|
|
@@ -49,8 +52,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
49
52
|
this.loaderIcon = 'https://archive.org/upload/images/tree/loading.gif';
|
|
50
53
|
this.disabled = false;
|
|
51
54
|
this.returnUrl = '';
|
|
52
|
-
this.
|
|
53
|
-
this.autoRenewTimeConfig = {};
|
|
55
|
+
this.renewNow = false;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
updated(changed) {
|
|
@@ -61,17 +63,28 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
61
63
|
this.resetActions();
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
if (this.
|
|
65
|
-
this.
|
|
66
|
-
new CustomEvent('autoBrowseBook', {
|
|
67
|
-
detail: {
|
|
68
|
-
event: { 'autoRenewed1Hour': 'browseBook' },
|
|
69
|
-
},
|
|
70
|
-
})
|
|
71
|
-
);
|
|
66
|
+
if (changed.has('renewNow') && this.renewNow === true) {
|
|
67
|
+
this.dispatchLoanRenewEvent();
|
|
72
68
|
}
|
|
73
69
|
}
|
|
74
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
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
75
88
|
/**
|
|
76
89
|
* merge primaryActions and secondaryActions into dropdown
|
|
77
90
|
*/
|
|
@@ -5,44 +5,39 @@ export default class TimerCountdown extends LitElement {
|
|
|
5
5
|
return {
|
|
6
6
|
time: { type: Number },
|
|
7
7
|
autoCheckAt: { type: Number },
|
|
8
|
-
resetTimerCountdown: { type: Boolean },
|
|
9
8
|
};
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
constructor() {
|
|
13
12
|
super();
|
|
14
|
-
this.time =
|
|
13
|
+
this.time = 0;
|
|
15
14
|
this.autoCheckAt = 0;
|
|
15
|
+
|
|
16
|
+
// private props
|
|
16
17
|
this.timerInterval = undefined;
|
|
17
|
-
this.resetTimerCountdown = false;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
disconnectedCallback() {
|
|
21
|
-
clearInterval(this.timerInterval)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
firstUpdated() {
|
|
25
|
-
this.timerCountdown();
|
|
21
|
+
clearInterval(this.timerInterval);
|
|
26
22
|
}
|
|
27
23
|
|
|
28
24
|
updated(changed) {
|
|
29
|
-
if (changed.has('
|
|
25
|
+
if (changed.has('time') && this.time > 0) {
|
|
30
26
|
clearInterval(this.timerInterval);
|
|
31
|
-
this.timerCountdown()
|
|
27
|
+
this.timerCountdown();
|
|
32
28
|
}
|
|
33
29
|
}
|
|
34
|
-
|
|
30
|
+
|
|
35
31
|
timerCountdown() {
|
|
36
32
|
this.timerInterval = setInterval(() => {
|
|
37
33
|
this.time -= 1;
|
|
38
34
|
|
|
39
35
|
// execute 50th minute check
|
|
40
|
-
if (this.time === this.autoCheckAt) {
|
|
36
|
+
if (Math.round(this.time) === this.autoCheckAt) {
|
|
41
37
|
this.dispatchEvent(
|
|
42
|
-
new CustomEvent('
|
|
38
|
+
new CustomEvent('IABookActions:loanRenew', {
|
|
43
39
|
detail: {
|
|
44
|
-
|
|
45
|
-
bookPageChange: false,
|
|
40
|
+
isPageChanged: false,
|
|
46
41
|
},
|
|
47
42
|
bubbles: true,
|
|
48
43
|
composed: true,
|
|
@@ -51,18 +46,16 @@ export default class TimerCountdown extends LitElement {
|
|
|
51
46
|
}
|
|
52
47
|
|
|
53
48
|
if (this.time === 0) clearInterval(this.timerInterval);
|
|
54
|
-
|
|
55
49
|
}, 1000);
|
|
56
50
|
}
|
|
57
51
|
|
|
58
|
-
|
|
59
52
|
render() {
|
|
60
53
|
return html`<div id="countdown">
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
<div id="countdown-number">${Math.round(this.time)}</div>
|
|
55
|
+
<svg>
|
|
56
|
+
<circle r="18" cx="20" cy="20"></circle>
|
|
57
|
+
</svg>
|
|
58
|
+
</div>`;
|
|
66
59
|
}
|
|
67
60
|
|
|
68
61
|
static get styles() {
|
|
@@ -72,22 +65,14 @@ export default class TimerCountdown extends LitElement {
|
|
|
72
65
|
font-size: 14px;
|
|
73
66
|
position: absolute;
|
|
74
67
|
}
|
|
75
|
-
|
|
76
|
-
position: relative;
|
|
77
|
-
margin: auto;
|
|
78
|
-
margin-top: 100px;
|
|
79
|
-
height: 40px;
|
|
80
|
-
width: 40px;
|
|
81
|
-
text-align: center;
|
|
82
|
-
}
|
|
83
|
-
|
|
68
|
+
|
|
84
69
|
#countdown-number {
|
|
85
70
|
color: white;
|
|
86
71
|
display: inline-block;
|
|
87
72
|
line-height: 40px;
|
|
88
73
|
margin-right: 12px;
|
|
89
74
|
}
|
|
90
|
-
|
|
75
|
+
|
|
91
76
|
svg {
|
|
92
77
|
position: absolute;
|
|
93
78
|
top: 0;
|
|
@@ -96,7 +81,7 @@ export default class TimerCountdown extends LitElement {
|
|
|
96
81
|
height: 40px;
|
|
97
82
|
transform: rotateY(-180deg) rotateZ(-90deg);
|
|
98
83
|
}
|
|
99
|
-
|
|
84
|
+
|
|
100
85
|
svg circle {
|
|
101
86
|
stroke-dasharray: 113px;
|
|
102
87
|
stroke-dashoffset: 0px;
|
|
@@ -106,7 +91,7 @@ export default class TimerCountdown extends LitElement {
|
|
|
106
91
|
fill: none;
|
|
107
92
|
animation: countdown 60s linear infinite forwards;
|
|
108
93
|
}
|
|
109
|
-
|
|
94
|
+
|
|
110
95
|
@keyframes countdown {
|
|
111
96
|
from {
|
|
112
97
|
stroke-dashoffset: 0px;
|
|
@@ -115,6 +100,7 @@ export default class TimerCountdown extends LitElement {
|
|
|
115
100
|
stroke-dashoffset: 113px;
|
|
116
101
|
}
|
|
117
102
|
}
|
|
103
|
+
|
|
118
104
|
.hidden {
|
|
119
105
|
display: none;
|
|
120
106
|
}
|
|
@@ -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',
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
2
|
|
|
3
|
-
import { LocalCache } from '@internetarchive/local-cache';
|
|
4
3
|
import { URLHelper } from '../../config/url-helper.js';
|
|
5
4
|
import ActionsHandlerService from './actions-handler-service.js';
|
|
6
5
|
import * as Cookies from '../doc-cookies.js';
|
|
@@ -16,14 +15,7 @@ import * as Cookies from '../doc-cookies.js';
|
|
|
16
15
|
export default class ActionsHandler extends LitElement {
|
|
17
16
|
constructor() {
|
|
18
17
|
super();
|
|
19
|
-
this.identifier = '';
|
|
20
18
|
this.ajaxTimeout = 6000;
|
|
21
|
-
this.returnUrl = '';
|
|
22
|
-
this.autoRenewTimeConfig = {};
|
|
23
|
-
|
|
24
|
-
this.localCache = new LocalCache({
|
|
25
|
-
namespace: '1HourLoanStorage',
|
|
26
|
-
});
|
|
27
19
|
|
|
28
20
|
this.bindEvents();
|
|
29
21
|
}
|
|
@@ -36,7 +28,7 @@ export default class ActionsHandler extends LitElement {
|
|
|
36
28
|
);
|
|
37
29
|
}
|
|
38
30
|
|
|
39
|
-
|
|
31
|
+
bindEvents() {
|
|
40
32
|
this.addEventListener('browseBook', ({ detail }) => {
|
|
41
33
|
this.handleBrowseIt();
|
|
42
34
|
this.setConsecutiveLoanCounts();
|
|
@@ -51,9 +43,8 @@ export default class ActionsHandler extends LitElement {
|
|
|
51
43
|
this.sendEvent(category, action);
|
|
52
44
|
});
|
|
53
45
|
|
|
54
|
-
this.addEventListener('
|
|
55
|
-
|
|
56
|
-
this.handleAutoBrowseIt();
|
|
46
|
+
this.addEventListener('loanRenew', ({ detail }) => {
|
|
47
|
+
this.handleLoanRenew();
|
|
57
48
|
const { category, action } = detail.event;
|
|
58
49
|
this.sendEvent(category, action);
|
|
59
50
|
});
|
|
@@ -112,7 +103,7 @@ export default class ActionsHandler extends LitElement {
|
|
|
112
103
|
handleBrowseIt() {
|
|
113
104
|
const action = 'browse_book';
|
|
114
105
|
this.dispatchToggleActionGroup();
|
|
115
|
-
this.setBrowseTimeSession()
|
|
106
|
+
this.setBrowseTimeSession();
|
|
116
107
|
|
|
117
108
|
ActionsHandlerService({
|
|
118
109
|
action,
|
|
@@ -126,9 +117,9 @@ export default class ActionsHandler extends LitElement {
|
|
|
126
117
|
});
|
|
127
118
|
}
|
|
128
119
|
|
|
129
|
-
|
|
130
|
-
const action = '
|
|
131
|
-
this.setBrowseTimeSession()
|
|
120
|
+
handleLoanRenew() {
|
|
121
|
+
const action = 'renew_loan';
|
|
122
|
+
this.setBrowseTimeSession();
|
|
132
123
|
|
|
133
124
|
ActionsHandlerService({
|
|
134
125
|
action,
|
|
@@ -140,7 +131,6 @@ export default class ActionsHandler extends LitElement {
|
|
|
140
131
|
});
|
|
141
132
|
}
|
|
142
133
|
|
|
143
|
-
|
|
144
134
|
handleReturnIt() {
|
|
145
135
|
const action = 'return_loan';
|
|
146
136
|
this.dispatchToggleActionGroup();
|
|
@@ -291,6 +281,24 @@ export default class ActionsHandler extends LitElement {
|
|
|
291
281
|
}
|
|
292
282
|
}
|
|
293
283
|
|
|
284
|
+
/**
|
|
285
|
+
* set browse time in indexedDB
|
|
286
|
+
*/
|
|
287
|
+
async setBrowseTimeSession() {
|
|
288
|
+
try {
|
|
289
|
+
await this.localCache.set({
|
|
290
|
+
key: `${this.identifier}-loanTime`,
|
|
291
|
+
value: new Date(), // current time
|
|
292
|
+
ttl: Number(this.loanRenewConfig.totalTime),
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// delete flip time
|
|
296
|
+
await this.localCache.delete(`${this.identifier}-pageChangedTime`);
|
|
297
|
+
} catch (error) {
|
|
298
|
+
console.log(error);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
294
302
|
deleteLoanCookies() {
|
|
295
303
|
const date = new Date();
|
|
296
304
|
date.setTime(date.getTime() - 24 * 60 * 60 * 1000); // one day ago
|
|
@@ -310,17 +318,4 @@ export default class ActionsHandler extends LitElement {
|
|
|
310
318
|
'.archive.org'
|
|
311
319
|
);
|
|
312
320
|
}
|
|
313
|
-
|
|
314
|
-
async setBrowseTimeSession() {
|
|
315
|
-
try {
|
|
316
|
-
// set a value
|
|
317
|
-
await this.localCache.set({
|
|
318
|
-
key: `${this.identifier}-loanTime`,
|
|
319
|
-
value: new Date(), // current time
|
|
320
|
-
ttl: parseInt(this.autoRenewTimeConfig.totalTime),
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
await this.localCache.delete(`${this.identifier}-pageFlipTime`);
|
|
324
|
-
} catch (error) {}
|
|
325
|
-
}
|
|
326
321
|
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { nothing } from 'lit';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This class is used to determine if use is eligible for auto renew loan.
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
export class OneHourLoanRenew {
|
|
8
|
+
constructor(isPageChanged, identifier, localCache, loanRenewConfig) {
|
|
9
|
+
this.isPageChanged = isPageChanged;
|
|
10
|
+
this.identifier = identifier;
|
|
11
|
+
this.localCache = localCache;
|
|
12
|
+
this.loanRenewConfig = loanRenewConfig;
|
|
13
|
+
|
|
14
|
+
// messages for auto return machenism
|
|
15
|
+
this.loanRenewMessage = 'This book has been renewed for another hour.';
|
|
16
|
+
this.loanReturnMessage =
|
|
17
|
+
'This book has been auto-returned due to inactivity.';
|
|
18
|
+
this.loanReturnWarning =
|
|
19
|
+
'This book will be auto-returned in 10 minutes unless you turn a page.';
|
|
20
|
+
|
|
21
|
+
// private props
|
|
22
|
+
this.loanRenewResult = {
|
|
23
|
+
texts: null,
|
|
24
|
+
renewNow: false,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return this.handleLoanRenew();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
handleLoanRenew() {
|
|
31
|
+
try {
|
|
32
|
+
// when user click/flip on book page
|
|
33
|
+
if (this.isPageChanged) {
|
|
34
|
+
console.log('page changed!!');
|
|
35
|
+
return this.pageChanged(); // user clicked on page
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return this.autoChecker(); // auto checker at 50th minute
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.log(error);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return nothing;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async pageChanged() {
|
|
47
|
+
const {
|
|
48
|
+
totalTime, // 60
|
|
49
|
+
autoCheckAt, // 50
|
|
50
|
+
} = this.loanRenewConfig;
|
|
51
|
+
const currentTime = new Date();
|
|
52
|
+
const loanTime = await this.localCache.get(`${this.identifier}-loanTime`);
|
|
53
|
+
|
|
54
|
+
const lastTimeFrame = this.changeTime(
|
|
55
|
+
loanTime,
|
|
56
|
+
totalTime - autoCheckAt,
|
|
57
|
+
'add'
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// if user viewed new page in last 10 minutes, renew immediately
|
|
61
|
+
if (currentTime >= lastTimeFrame) {
|
|
62
|
+
console.log('Yes, borrow it again now!');
|
|
63
|
+
this.loanRenewResult.texts = this.loanRenewMessage;
|
|
64
|
+
this.loanRenewResult.renewNow = true;
|
|
65
|
+
|
|
66
|
+
this.setLoanRenewedTime();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.setPageChangedTime();
|
|
70
|
+
return this.loanRenewResult;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async autoChecker() {
|
|
74
|
+
const currentTime = new Date();
|
|
75
|
+
const { pageChangedInLast } = this.loanRenewConfig;
|
|
76
|
+
const lastPageFlipTime = await this.localCache.get(
|
|
77
|
+
`${this.identifier}-pageChangedTime`
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// last 15 min if used flipped a page.
|
|
81
|
+
const lastFlipTimeFrame = this.changeTime(
|
|
82
|
+
currentTime,
|
|
83
|
+
pageChangedInLast,
|
|
84
|
+
'sub'
|
|
85
|
+
); // 15 seconds
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
lastPageFlipTime === undefined ||
|
|
89
|
+
lastPageFlipTime <= lastFlipTimeFrame
|
|
90
|
+
) {
|
|
91
|
+
// not viewed
|
|
92
|
+
console.log("Not viewed, don't borrow it!");
|
|
93
|
+
this.loanRenewResult.texts = this.loanReturnWarning;
|
|
94
|
+
this.loanRenewResult.renewNow = false;
|
|
95
|
+
} else if (lastPageFlipTime >= lastFlipTimeFrame) {
|
|
96
|
+
// viewed in last time frame
|
|
97
|
+
console.log('Yes viewed, borrow it again!');
|
|
98
|
+
this.loanRenewResult.texts = this.loanRenewMessage;
|
|
99
|
+
this.loanRenewResult.renewNow = true;
|
|
100
|
+
|
|
101
|
+
this.setLoanRenewedTime();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return this.loanRenewResult;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// save page changed time in indexedDB
|
|
108
|
+
async setPageChangedTime() {
|
|
109
|
+
await this.localCache.set({
|
|
110
|
+
key: `${this.identifier}-pageChangedTime`,
|
|
111
|
+
value: new Date(), // current time
|
|
112
|
+
ttl: Number(this.loanRenewConfig.totalTime),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async setLoanRenewedTime() {
|
|
117
|
+
try {
|
|
118
|
+
// last 15 min if used flipped a page.
|
|
119
|
+
const expireDate = this.changeTime(
|
|
120
|
+
new Date(),
|
|
121
|
+
this.loanRenewConfig.totalTime,
|
|
122
|
+
'add'
|
|
123
|
+
); // 15 seconds
|
|
124
|
+
|
|
125
|
+
// set a value
|
|
126
|
+
await this.localCache.set({
|
|
127
|
+
key: `${this.identifier}-loanTime`,
|
|
128
|
+
value: expireDate, // expireDate time
|
|
129
|
+
ttl: Number(this.loanRenewConfig.totalTime),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// delete pageChangedTime when book is auto renew at nth minute
|
|
133
|
+
await this.localCache.delete(`${this.identifier}-pageChangedTime`);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.log(error);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
changeTime(date, minutes, op) {
|
|
140
|
+
if (date === undefined) return nothing;
|
|
141
|
+
|
|
142
|
+
if (op === 'sub') {
|
|
143
|
+
return new Date(date.getTime() - minutes * 1000);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return new Date(date.getTime() + minutes * 1000);
|
|
147
|
+
}
|
|
148
|
+
}
|
package/src/ia-book-actions.js
CHANGED
|
@@ -3,6 +3,8 @@ 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 '@internetarchive/toast-manager';
|
|
7
|
+
import { ToastConfig } from '@internetarchive/toast-manager';
|
|
6
8
|
import { LocalCache } from '@internetarchive/local-cache';
|
|
7
9
|
|
|
8
10
|
import './components/collapsible-action-group.js';
|
|
@@ -10,12 +12,11 @@ import './components/book-title-bar.js';
|
|
|
10
12
|
import './components/text-group.js';
|
|
11
13
|
import './components/info-icon.js';
|
|
12
14
|
import './components/timer-countdown.js';
|
|
13
|
-
import './components/toast-message.js';
|
|
14
15
|
|
|
15
|
-
import { GetLendingActions } from './core/services/get-lending-actions.js';
|
|
16
16
|
import { mobileContainerWidth } from './core/config/constants.js';
|
|
17
|
+
import { GetLendingActions } from './core/services/get-lending-actions.js';
|
|
17
18
|
import { LoanTokenPoller } from './core/services/loan-token-poller.js';
|
|
18
|
-
import {
|
|
19
|
+
import { OneHourLoanRenew } from './core/services/one-hour-loan-renew.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
|
+
loanRenewConfig: { type: Object },
|
|
46
|
+
loanRenewResult: { type: Object },
|
|
50
47
|
};
|
|
51
48
|
}
|
|
52
49
|
|
|
@@ -61,15 +58,21 @@ 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
64
|
this.tokenDelay = 120000; // 2 minutes
|
|
69
65
|
this.localCache = new LocalCache({
|
|
70
|
-
namespace: '
|
|
71
|
-
})
|
|
72
|
-
|
|
66
|
+
namespace: 'loanRenew',
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// loan auto renew
|
|
70
|
+
this.isPageChanged = false;
|
|
71
|
+
this.loanRenewConfig = {};
|
|
72
|
+
this.loanRenewResult = {
|
|
73
|
+
texts: null,
|
|
74
|
+
renewNow: false,
|
|
75
|
+
};
|
|
73
76
|
|
|
74
77
|
// private props
|
|
75
78
|
this.primaryActions = [];
|
|
@@ -79,12 +82,10 @@ export default class IABookActions extends LitElement {
|
|
|
79
82
|
this.lendingOptions = {};
|
|
80
83
|
this.borrowType = ''; // (browsed|borrowed)
|
|
81
84
|
this.consecutiveLoanCounts = 1; // consecutive loan count
|
|
82
|
-
this.browseAgainNow = false;
|
|
83
85
|
this.browserTimer = undefined;
|
|
84
|
-
this.hideToast = true;
|
|
85
86
|
|
|
86
|
-
this.
|
|
87
|
-
this.
|
|
87
|
+
this._shadowRoot = this.attachShadow({ mode: "open" });
|
|
88
|
+
this.bindLoanRenewEvents();
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
disconnectedCallback() {
|
|
@@ -106,35 +107,66 @@ export default class IABookActions extends LitElement {
|
|
|
106
107
|
this.update();
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
if (changed.has('autoRenew')) {
|
|
110
|
-
this.resetTimerCountdown = true;
|
|
111
|
-
}
|
|
112
110
|
if (changed.has('sharedObserver')) {
|
|
113
111
|
this.disconnectResizeObserver();
|
|
114
112
|
this.setupResizeObserver();
|
|
115
113
|
}
|
|
116
114
|
}
|
|
117
115
|
|
|
118
|
-
|
|
119
|
-
// dispatched this event from
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
this.identifier,
|
|
126
|
-
this.localCache,
|
|
127
|
-
this.autoRenewTimeConfig,
|
|
128
|
-
this.lendingStatus.user_has_browsed && !this.lendingStatus.browsingExpired
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
this.toastTexts = dd.toastTexts;
|
|
132
|
-
this.hideToast = dd.hideToast;
|
|
133
|
-
this.browseAgainNow = dd.renewNow;
|
|
134
|
-
if (this.browseAgainNow) {
|
|
135
|
-
await this.browseHasRenew();
|
|
116
|
+
bindLoanRenewEvents() {
|
|
117
|
+
// dispatched this event from bookreader page changed
|
|
118
|
+
window.addEventListener('BookReader:pageChanged', () => {
|
|
119
|
+
// early return if book is not browsed (1 hour borrow)
|
|
120
|
+
if (this.borrowType === 'browsed') {
|
|
121
|
+
this.isPageChanged = true;
|
|
122
|
+
this.executeLoanRenew();
|
|
136
123
|
}
|
|
137
|
-
|
|
124
|
+
|
|
125
|
+
return nothing;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// dispatched this event from timer-countdown
|
|
129
|
+
this.addEventListener('IABookActions:loanRenew', () => {
|
|
130
|
+
this.isPageChanged = false;
|
|
131
|
+
this.executeLoanRenew();
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async executeLoanRenew() {
|
|
136
|
+
this.loanRenewResult = await new OneHourLoanRenew(
|
|
137
|
+
this.isPageChanged,
|
|
138
|
+
this.identifier,
|
|
139
|
+
this.localCache,
|
|
140
|
+
this.loanRenewConfig
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
console.log(this.loanRenewResult);
|
|
144
|
+
|
|
145
|
+
this.showToastMessage();
|
|
146
|
+
|
|
147
|
+
if (this.loanRenewResult.renewNow) {
|
|
148
|
+
this.tokenPoller.disconnectedInterval();
|
|
149
|
+
await this.browseHasRenew();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return nothing;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async showToastMessage() {
|
|
156
|
+
let toastTemplate = this.shadowRoot.querySelector('toast-template');
|
|
157
|
+
if (!toastTemplate) {
|
|
158
|
+
toastTemplate = document.createElement('toast-template');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
await this.shadowRoot.appendChild(toastTemplate)
|
|
162
|
+
// await document.body.appendChild(toastTemplate);
|
|
163
|
+
|
|
164
|
+
const config = new ToastConfig();
|
|
165
|
+
config.texts = this.loanRenewResult?.texts;
|
|
166
|
+
config.dismisOnClick = true;
|
|
167
|
+
|
|
168
|
+
toastTemplate.showToast({
|
|
169
|
+
config
|
|
138
170
|
});
|
|
139
171
|
}
|
|
140
172
|
|
|
@@ -144,18 +176,25 @@ export default class IABookActions extends LitElement {
|
|
|
144
176
|
|
|
145
177
|
// remove respected key:value
|
|
146
178
|
await this.localCache.delete(`${this.identifier}-loanTime`);
|
|
147
|
-
await this.localCache.delete(`${this.identifier}-
|
|
179
|
+
await this.localCache.delete(`${this.identifier}-pageChangedTime`);
|
|
148
180
|
|
|
149
181
|
// show message after browsed book is expired.
|
|
150
|
-
this.
|
|
182
|
+
this.loanRenewResult.renewNow = false;
|
|
183
|
+
this.loanRenewResult.texts =
|
|
184
|
+
'This book has been auto-returned due to inactivity.';
|
|
185
|
+
|
|
186
|
+
this.showToastMessage();
|
|
151
187
|
}
|
|
152
188
|
|
|
153
189
|
async browseHasRenew() {
|
|
154
|
-
const
|
|
190
|
+
const loanTime = await this.localCache.get(`${this.identifier}-loanTime`);
|
|
191
|
+
const secondsLeft = (loanTime - new Date()) / 1000; // different in seconds
|
|
192
|
+
|
|
193
|
+
const currStatus = {
|
|
155
194
|
...this.lendingStatus,
|
|
156
195
|
user_has_browsed: true,
|
|
157
196
|
browsingExpired: false,
|
|
158
|
-
secondsLeftOnLoan:
|
|
197
|
+
secondsLeftOnLoan: secondsLeft,
|
|
159
198
|
};
|
|
160
199
|
this.lendingStatus = currStatus;
|
|
161
200
|
|
|
@@ -174,7 +213,6 @@ export default class IABookActions extends LitElement {
|
|
|
174
213
|
return;
|
|
175
214
|
}
|
|
176
215
|
|
|
177
|
-
// expired book and show browse again button
|
|
178
216
|
const timeLeft = secondsLeftOnLoan * 1000;
|
|
179
217
|
this.browserTimer = setTimeout(() => {
|
|
180
218
|
this.browseHasExpired();
|
|
@@ -234,13 +272,16 @@ export default class IABookActions extends LitElement {
|
|
|
234
272
|
});
|
|
235
273
|
|
|
236
274
|
this.borrowType = actions.borrowType;
|
|
237
|
-
this.remainingTime = this.lendingStatus.secondsLeftOnLoan;
|
|
238
275
|
|
|
239
276
|
const hasExpired =
|
|
240
277
|
'browsingExpired' in this.lendingStatus &&
|
|
241
278
|
this.lendingStatus?.browsingExpired;
|
|
242
279
|
if (hasExpired) {
|
|
243
|
-
|
|
280
|
+
if (!this.tokenPoller.disconnectedInterval) {
|
|
281
|
+
window?.Sentry?.captureMessage(
|
|
282
|
+
'setupLendingToolbarActions hasExpired - no tokenPoller'
|
|
283
|
+
);
|
|
284
|
+
}
|
|
244
285
|
this.tokenPoller?.disconnectedInterval();
|
|
245
286
|
/** Global event - always fire */
|
|
246
287
|
this.dispatchEvent(
|
|
@@ -265,7 +306,16 @@ export default class IABookActions extends LitElement {
|
|
|
265
306
|
return;
|
|
266
307
|
}
|
|
267
308
|
|
|
268
|
-
|
|
309
|
+
// if (book is about to renew)
|
|
310
|
+
// - start token to poller around this.tokenDelay time until renew is completed
|
|
311
|
+
// else
|
|
312
|
+
// - start token poller immediately
|
|
313
|
+
setTimeout(
|
|
314
|
+
() => {
|
|
315
|
+
this.startLoanTokenPoller();
|
|
316
|
+
},
|
|
317
|
+
this.loanRenewResult.renewNow ? this.tokenDelay : 100
|
|
318
|
+
);
|
|
269
319
|
}
|
|
270
320
|
|
|
271
321
|
render() {
|
|
@@ -290,26 +340,14 @@ export default class IABookActions extends LitElement {
|
|
|
290
340
|
get timerCountdownTemplate() {
|
|
291
341
|
return this.borrowType === 'browsed'
|
|
292
342
|
? html`<timer-countdown
|
|
293
|
-
time=${Number(this.
|
|
294
|
-
.autoCheckAt=${this.
|
|
295
|
-
?resetTimerCountdown=${this.resetTimerCountdown}
|
|
343
|
+
time=${Number(this.lendingStatus.secondsLeftOnLoan)}
|
|
344
|
+
.autoCheckAt=${this.loanRenewConfig.autoCheckAt}
|
|
296
345
|
></timer-countdown>`
|
|
297
346
|
: nothing;
|
|
298
347
|
}
|
|
299
348
|
|
|
300
|
-
get toastMessageTemplate() {
|
|
301
|
-
return html`
|
|
302
|
-
<toast-message
|
|
303
|
-
.texts=${this.toastTexts}
|
|
304
|
-
.dismisOnClick="1"
|
|
305
|
-
?hideToast=${this.hideToast}
|
|
306
|
-
></toast-message>
|
|
307
|
-
`;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
349
|
get bookActionBar() {
|
|
311
350
|
return html`
|
|
312
|
-
<button @click=${() => this.pageFlipEvent()}>Page Flip</button>
|
|
313
351
|
<collapsible-action-group
|
|
314
352
|
.userid=${this.userid}
|
|
315
353
|
.identifier=${this.identifier}
|
|
@@ -319,32 +357,20 @@ export default class IABookActions extends LitElement {
|
|
|
319
357
|
.width=${this.width}
|
|
320
358
|
.borrowType=${this.borrowType}
|
|
321
359
|
.returnUrl=${this.returnUrl}
|
|
322
|
-
.
|
|
323
|
-
.
|
|
360
|
+
.localCache=${this.localCache}
|
|
361
|
+
.loanRenewConfig=${this.loanRenewConfig}
|
|
324
362
|
?hasAdminAccess=${this.hasAdminAccess}
|
|
325
363
|
?disabled=${this.disableActionGroup}
|
|
326
|
-
?
|
|
364
|
+
?renewNow=${this.loanRenewResult.renewNow}
|
|
327
365
|
@lendingActionError=${this.handleLendingActionError}
|
|
328
366
|
@toggleActionGroup=${this.handleToggleActionGroup}
|
|
329
367
|
>
|
|
330
368
|
</collapsible-action-group>
|
|
331
369
|
${this.textGroupTemplate} ${this.infoIconTemplate}
|
|
332
|
-
${this.timerCountdownTemplate}
|
|
370
|
+
${this.timerCountdownTemplate}
|
|
333
371
|
`;
|
|
334
372
|
}
|
|
335
373
|
|
|
336
|
-
// will move this function to bookreader...
|
|
337
|
-
async pageFlipEvent() {
|
|
338
|
-
try {
|
|
339
|
-
// dispatch event to say book page has flipped
|
|
340
|
-
document.querySelector("ia-book-actions").dispatchEvent(
|
|
341
|
-
new CustomEvent("autoRenewAttempt", {
|
|
342
|
-
detail: { bookPageChange: true },
|
|
343
|
-
})
|
|
344
|
-
);
|
|
345
|
-
} catch (error) { console.log(error) }
|
|
346
|
-
}
|
|
347
|
-
|
|
348
374
|
/**
|
|
349
375
|
* enable access of borrowed/browsed books
|
|
350
376
|
*/
|
|
@@ -485,7 +511,7 @@ export default class IABookActions extends LitElement {
|
|
|
485
511
|
get textGroupTemplate() {
|
|
486
512
|
return html`<text-group
|
|
487
513
|
textClass=${this.textClass}
|
|
488
|
-
texts=${this.primaryTitle}
|
|
514
|
+
.texts=${this.primaryTitle}
|
|
489
515
|
>
|
|
490
516
|
</text-group>`;
|
|
491
517
|
}
|
|
@@ -498,20 +524,23 @@ export default class IABookActions extends LitElement {
|
|
|
498
524
|
return css`
|
|
499
525
|
:host {
|
|
500
526
|
display: block;
|
|
501
|
-
background: var(--primaryBGColor, #000);
|
|
502
|
-
color: var(--primaryTextColor, #fff);
|
|
503
527
|
}
|
|
528
|
+
|
|
504
529
|
.lending-wrapper {
|
|
505
530
|
width: 100%;
|
|
506
531
|
margin: 0 auto;
|
|
532
|
+
background: var(--primaryBGColor, #000);
|
|
533
|
+
color: var(--primaryTextColor, #fff);
|
|
507
534
|
display: inline-flex;
|
|
508
535
|
align-items: center;
|
|
509
536
|
justify-content: center;
|
|
510
537
|
flex-wrap: wrap;
|
|
511
538
|
}
|
|
512
539
|
|
|
513
|
-
toast-
|
|
514
|
-
--
|
|
540
|
+
toast-template {
|
|
541
|
+
--toastTopMargin: 80px;
|
|
542
|
+
--toastBGColor: #333;
|
|
543
|
+
--toastFontColor: #fff;
|
|
515
544
|
}
|
|
516
545
|
`;
|
|
517
546
|
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { css } from 'lit';
|
|
2
|
-
|
|
3
|
-
export default timerCountDownStyle = css`
|
|
4
|
-
:host {
|
|
5
|
-
right: 5px;
|
|
6
|
-
font-size: 14px;
|
|
7
|
-
position: absolute;
|
|
8
|
-
}
|
|
9
|
-
#countdown1 {
|
|
10
|
-
position: relative;
|
|
11
|
-
margin: auto;
|
|
12
|
-
margin-top: 100px;
|
|
13
|
-
height: 40px;
|
|
14
|
-
width: 40px;
|
|
15
|
-
text-align: center;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
#countdown-number {
|
|
19
|
-
color: white;
|
|
20
|
-
display: inline-block;
|
|
21
|
-
line-height: 40px;
|
|
22
|
-
margin-right: 12px;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
svg {
|
|
26
|
-
position: absolute;
|
|
27
|
-
top: 0;
|
|
28
|
-
right: 0;
|
|
29
|
-
width: 40px;
|
|
30
|
-
height: 40px;
|
|
31
|
-
transform: rotateY(-180deg) rotateZ(-90deg);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
svg circle {
|
|
35
|
-
stroke-dasharray: 113px;
|
|
36
|
-
stroke-dashoffset: 0px;
|
|
37
|
-
stroke-linecap: round;
|
|
38
|
-
stroke-width: 3px;
|
|
39
|
-
stroke: white;
|
|
40
|
-
fill: none;
|
|
41
|
-
animation: countdown 60s linear infinite forwards;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@keyframes countdown {
|
|
45
|
-
from {
|
|
46
|
-
stroke-dashoffset: 0px;
|
|
47
|
-
}
|
|
48
|
-
to {
|
|
49
|
-
stroke-dashoffset: 113px;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
.hidden {
|
|
53
|
-
display: none;
|
|
54
|
-
}
|
|
55
|
-
.visible {
|
|
56
|
-
display: inline-block;
|
|
57
|
-
}
|
|
58
|
-
`;
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { html, css, LitElement, nothing } from 'lit';
|
|
2
|
-
|
|
3
|
-
export class ToastMessage extends LitElement {
|
|
4
|
-
static get properties() {
|
|
5
|
-
return {
|
|
6
|
-
texts: { type: String },
|
|
7
|
-
dismisOnClick: { type: Function },
|
|
8
|
-
hideToast: { type: Boolean },
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
constructor() {
|
|
13
|
-
super();
|
|
14
|
-
this.texts = '';
|
|
15
|
-
this.textClass = '';
|
|
16
|
-
this.hideToast = false;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
render() {
|
|
20
|
-
return !this.hideToast
|
|
21
|
-
? html`
|
|
22
|
-
<span class="toast-message ${this.textClass}">${this.texts}</span>
|
|
23
|
-
`
|
|
24
|
-
: nothing;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
static get styles() {
|
|
28
|
-
const heightFromTop = css`var(--messageHeightFromTop, 15%)`;
|
|
29
|
-
|
|
30
|
-
return css`
|
|
31
|
-
:host {
|
|
32
|
-
display: inline-block;
|
|
33
|
-
}
|
|
34
|
-
.toast-message {
|
|
35
|
-
z-index: 2;
|
|
36
|
-
position: absolute;
|
|
37
|
-
top: ${heightFromTop};
|
|
38
|
-
font-size: 1.4rem;
|
|
39
|
-
color: #fff;
|
|
40
|
-
left: 50%;
|
|
41
|
-
right: 50%;
|
|
42
|
-
background: #333;
|
|
43
|
-
border: 1px solid #fff;
|
|
44
|
-
border-radius: 5px;
|
|
45
|
-
box-shadow: 1px 1px 2px;
|
|
46
|
-
padding: 10px;
|
|
47
|
-
width: fit-content;
|
|
48
|
-
transform: translate(-50%, -50%);
|
|
49
|
-
}
|
|
50
|
-
.hidden {
|
|
51
|
-
display: none;
|
|
52
|
-
}
|
|
53
|
-
.visible {
|
|
54
|
-
display: inline-block;
|
|
55
|
-
}
|
|
56
|
-
`;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
window.customElements.define('toast-message', ToastMessage);
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import ActionsHandlerService from './actions-handler/actions-handler-service.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* This class is used to determine if use is eligible for auto renew loan.
|
|
5
|
-
*
|
|
6
|
-
* ActionsHandlerService is a function being used to execute
|
|
7
|
-
*/
|
|
8
|
-
export class OneHourAutoRenew {
|
|
9
|
-
constructor(pageClick, identifier, localCache, autoRenewTimeConfig, userHasBrowsed) {
|
|
10
|
-
this.pageClick = pageClick;
|
|
11
|
-
this.identifier = identifier;
|
|
12
|
-
this.localCache = localCache;
|
|
13
|
-
this.autoRenewTimeConfig = autoRenewTimeConfig;
|
|
14
|
-
this.userHasBrowsed = userHasBrowsed;
|
|
15
|
-
|
|
16
|
-
// private props
|
|
17
|
-
this.resultRes = {
|
|
18
|
-
toastTexts: null,
|
|
19
|
-
hideToast: true,
|
|
20
|
-
renewNow: false,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// messages for auto return machenism
|
|
24
|
-
this.autoRenewMessage = 'This book has been renewed for another hour.';
|
|
25
|
-
this.autoReturnMessage = 'This book has been auto-returned due to inactivity.';
|
|
26
|
-
this.autoReturnWarning = 'This book will be auto-returned in 10 minutes unless you turn a page.';
|
|
27
|
-
|
|
28
|
-
return this.handleBookAutoRenew();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async handleBookAutoRenew() {
|
|
32
|
-
try {
|
|
33
|
-
// if page is not flipped in last 15 minutes,
|
|
34
|
-
// instantaly renew it if user viewed new page in last 10 minutes
|
|
35
|
-
if (this.pageClick) {
|
|
36
|
-
console.log('page flipped!')
|
|
37
|
-
this.setPageFlippedTime();
|
|
38
|
-
return this.userFlippedBookPage(); // user clicked on page
|
|
39
|
-
} else {
|
|
40
|
-
console.log('auto checker!')
|
|
41
|
-
return this.autoCheckerTimer(); // auto checker at 50th minute
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.log(error)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async setPageFlippedTime() {
|
|
50
|
-
// set pageFlipTime time in localStorage
|
|
51
|
-
await this.localCache.set({
|
|
52
|
-
key: `${this.identifier}-pageFlipTime`,
|
|
53
|
-
value: new Date(), // current time
|
|
54
|
-
ttl: parseInt(this.autoRenewTimeConfig.totalTime),
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async userFlippedBookPage() {
|
|
59
|
-
const {
|
|
60
|
-
totalTime, // 60
|
|
61
|
-
autoCheckAt, // 50
|
|
62
|
-
} = this.autoRenewTimeConfig;
|
|
63
|
-
const currentDate = new Date();
|
|
64
|
-
const loanTime = await this.localCache.get(`${this.identifier}-loanTime`);
|
|
65
|
-
|
|
66
|
-
const lastTimeFrame = await this.changeTime(
|
|
67
|
-
loanTime,
|
|
68
|
-
totalTime - autoCheckAt,
|
|
69
|
-
'add'
|
|
70
|
-
); // 50 seconds
|
|
71
|
-
|
|
72
|
-
if (currentDate >= lastTimeFrame) {
|
|
73
|
-
console.log('1 YES NOW BORROW IT AGAIN NOW!');
|
|
74
|
-
this.resultRes.toastTexts = this.autoRenewMessage;
|
|
75
|
-
this.resultRes.browseAgainNow = true;
|
|
76
|
-
this.resultRes.hideToast = false;
|
|
77
|
-
this.resultRes.renewNow = true;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return this.resultRes;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async autoCheckerTimer() {
|
|
84
|
-
const currentDate = new Date();
|
|
85
|
-
const { FlippedInLast } = this.autoRenewTimeConfig;
|
|
86
|
-
const lastPageFlipTime = await this.localCache.get(`${this.identifier}-pageFlipTime`);
|
|
87
|
-
|
|
88
|
-
// last 15 min if used flipped a page.
|
|
89
|
-
const lastFlipTimeFrame = await this.changeTime(
|
|
90
|
-
currentDate,
|
|
91
|
-
FlippedInLast,
|
|
92
|
-
'sub'
|
|
93
|
-
); // 15 seconds
|
|
94
|
-
|
|
95
|
-
if (lastPageFlipTime === undefined || lastPageFlipTime <= lastFlipTimeFrame) { // not viewed
|
|
96
|
-
console.log('2');
|
|
97
|
-
this.resultRes.toastTexts = this.autoReturnWarning;
|
|
98
|
-
this.resultRes.hideToast = false;
|
|
99
|
-
} else if (lastPageFlipTime >= lastFlipTimeFrame) { // viewed in last time frame
|
|
100
|
-
console.log('3');
|
|
101
|
-
this.resultRes.toastTexts = this.autoRenewMessage;
|
|
102
|
-
this.resultRes.browseAgainNow = true;
|
|
103
|
-
this.resultRes.hideToast = false;
|
|
104
|
-
this.resultRes.renewNow = true;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return this.resultRes;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async changeTime(date, minutes, op) {
|
|
111
|
-
if (date === undefined) return undefined;
|
|
112
|
-
|
|
113
|
-
if (op === 'sub') {
|
|
114
|
-
return new Date(date.getTime() - minutes * 1000);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return new Date(date.getTime() + minutes * 1000);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
sendEvent(eventCategory, eventAction) {
|
|
122
|
-
window?.archive_analytics?.send_event(
|
|
123
|
-
eventCategory,
|
|
124
|
-
eventAction,
|
|
125
|
-
`identifier=${this.identifier}`
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
async handleAutoRenew() {
|
|
130
|
-
const action = 'renew_loan';
|
|
131
|
-
ActionsHandlerService({
|
|
132
|
-
identifier: this.identifier,
|
|
133
|
-
action,
|
|
134
|
-
error: data => {
|
|
135
|
-
window?.Sentry?.captureMessage(
|
|
136
|
-
'handleAutoRenew error',
|
|
137
|
-
JSON.stringify(data)
|
|
138
|
-
);
|
|
139
|
-
// this.errorCallback({ detail: { action, data } });
|
|
140
|
-
// send LendingServiceError to GA
|
|
141
|
-
this.sendEvent('handleAutoRenew', action);
|
|
142
|
-
},
|
|
143
|
-
success: () => {
|
|
144
|
-
return 'success';
|
|
145
|
-
},
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
}
|