@internetarchive/ia-book-actions 1.1.0-alpha9 → 1.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/.github/workflows/ci.yml +26 -0
- package/.github/workflows/gh-pages-main.yml +39 -0
- package/.github/workflows/pr-preview.yml +37 -0
- package/demo/index.html +44 -8
- package/index.html +474 -0
- package/package.json +15 -7
- package/src/assets/data/lending-get-status-service.js +1 -1
- package/src/components/timer-countdown.js +3 -2
- package/src/core/services/actions-handler/actions-handler-service.js +8 -3
- package/src/core/services/log.js +2 -1
- package/src/ia-book-actions.js +83 -67
- package/test/components/timer-countdown.test.js +3 -2
- package/test/ia-book-actions.test.js +57 -1
- package/vite.config.ts +22 -0
- package/web-dev-server.config.mjs +1 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: App CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-node@v3
|
|
16
|
+
with:
|
|
17
|
+
node-version: 16.x
|
|
18
|
+
|
|
19
|
+
- name: Install dependencies
|
|
20
|
+
run: yarn install
|
|
21
|
+
|
|
22
|
+
# - name: Run tests
|
|
23
|
+
# run: yarn run test
|
|
24
|
+
|
|
25
|
+
# - name: Upload reports
|
|
26
|
+
# run: npx codecov
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# This workflow will generate the static page under `main` subdirectory inside the `gh-pages` branch
|
|
2
|
+
|
|
3
|
+
# This workflow will run every time new changes were pushed to the `main` branch
|
|
4
|
+
|
|
5
|
+
name: App build CI/CD to main branch
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
branches: [ main ]
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
with:
|
|
18
|
+
persist-credentials: false
|
|
19
|
+
|
|
20
|
+
- uses: actions/setup-node@v3
|
|
21
|
+
with:
|
|
22
|
+
node-version: 20
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: yarn install
|
|
26
|
+
|
|
27
|
+
- name: Create build files for gh-pages deploy
|
|
28
|
+
run: yarn prepare:ghpages
|
|
29
|
+
|
|
30
|
+
# Reference: https://github.com/JamesIves/github-pages-deploy-action
|
|
31
|
+
- name: Deploy 🚀
|
|
32
|
+
uses: JamesIves/github-pages-deploy-action@v4.4.3
|
|
33
|
+
with:
|
|
34
|
+
branch: gh-pages
|
|
35
|
+
folder: ghpages
|
|
36
|
+
clean-exclude: pr/
|
|
37
|
+
force: false
|
|
38
|
+
target-folder: main
|
|
39
|
+
token: ${{ secrets.GH_TOKEN }}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# This workflow will generate the static page under `pr` subdirectory inside the `gh-pages` branch
|
|
2
|
+
|
|
3
|
+
# This workflow will run every time there's a PR opened, reopened, synchronize, or closed
|
|
4
|
+
|
|
5
|
+
name: Deploy PR previews
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
pull_request:
|
|
9
|
+
types:
|
|
10
|
+
- opened
|
|
11
|
+
- reopened
|
|
12
|
+
- synchronize
|
|
13
|
+
- closed
|
|
14
|
+
|
|
15
|
+
concurrency: preview-${{ github.ref }}
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
deploy-preview:
|
|
19
|
+
runs-on: ubuntu-20.04
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- uses: actions/setup-node@v3
|
|
25
|
+
with:
|
|
26
|
+
node-version: 20.x
|
|
27
|
+
|
|
28
|
+
- name: Install and Build
|
|
29
|
+
run: |
|
|
30
|
+
yarn install
|
|
31
|
+
yarn prepare:ghpages
|
|
32
|
+
# Reference: https://github.com/rossjrw/pr-preview-action
|
|
33
|
+
- name: Deploy preview
|
|
34
|
+
uses: rossjrw/pr-preview-action@v1
|
|
35
|
+
with:
|
|
36
|
+
source-dir: ./ghpages/
|
|
37
|
+
umbrella-dir: pr
|
package/demo/index.html
CHANGED
|
@@ -76,6 +76,13 @@
|
|
|
76
76
|
display: inline-grid;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
.action-button button {
|
|
80
|
+
padding: 6px;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
border: 2px solid #194880;
|
|
83
|
+
border-radius: 10px;
|
|
84
|
+
}
|
|
85
|
+
|
|
79
86
|
body.modal-manager-open {
|
|
80
87
|
overflow: hidden;
|
|
81
88
|
}
|
|
@@ -128,10 +135,11 @@
|
|
|
128
135
|
iaBookActions.modalConfig = modalConfig;
|
|
129
136
|
iaBookActions.lendingBarPostInit = lendingBarPostInit;
|
|
130
137
|
iaBookActions.tokenDelay = 2; // 2 seconds
|
|
138
|
+
iaBookActions.timerExecutionSeconds = 4 // 4 seconds
|
|
131
139
|
iaBookActions.returnUrl = '';
|
|
132
140
|
iaBookActions.localCache = localCache;
|
|
133
141
|
|
|
134
|
-
let loanTotalTime2Min = { loanTotalTime:
|
|
142
|
+
let loanTotalTime2Min = { loanTotalTime: 120, loanRenewAtLast: 80, pageChangedInLast: 15 };
|
|
135
143
|
let loanTotalTime5Min = { loanTotalTime: 300, loanRenewAtLast: 180, pageChangedInLast: 15 };
|
|
136
144
|
let loanTotalTime1Hour = { loanTotalTime: 3600, loanRenewAtLast: 660, pageChangedInLast: 900 };
|
|
137
145
|
|
|
@@ -286,6 +294,19 @@
|
|
|
286
294
|
iaBookActions.browseHasExpired();
|
|
287
295
|
});
|
|
288
296
|
|
|
297
|
+
document.querySelector('#resync_timer').addEventListener('click', async (e) => {
|
|
298
|
+
if (iaBookActions.lendingStatus.user_has_browsed) {
|
|
299
|
+
document.querySelector('ia-book-actions').dispatchEvent(
|
|
300
|
+
new Event('visibilitychange', {
|
|
301
|
+
detail: {},
|
|
302
|
+
bubbles: true,
|
|
303
|
+
composed: true,
|
|
304
|
+
})
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
308
|
+
});
|
|
309
|
+
|
|
289
310
|
document.querySelectorAll('.availableToBorrow input[type=radio]').forEach((item) => {
|
|
290
311
|
item.addEventListener('click', (e) => {
|
|
291
312
|
if (e.target.value === 'available_to_borrow') {
|
|
@@ -359,8 +380,9 @@
|
|
|
359
380
|
</td>
|
|
360
381
|
<td class="searchParam">
|
|
361
382
|
<label><input type="checkbox" name="search" value="Search Param" />Search Param</label>
|
|
383
|
+
</td>
|
|
362
384
|
<td>
|
|
363
|
-
<button class="pageChangedEvent">Page Change Event</button>
|
|
385
|
+
<label class="ia-button"><button class="pageChangedEvent">Page Change Event</button></label>
|
|
364
386
|
</td>
|
|
365
387
|
</tr>
|
|
366
388
|
</table>
|
|
@@ -385,12 +407,6 @@
|
|
|
385
407
|
<label><input type="radio" name="browse" value="available_to_browse" />available_to_browse</label>
|
|
386
408
|
<label><input type="radio" name="browse" value="user_has_browsed" />user_has_browsed</label>
|
|
387
409
|
<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
|
-
</div>
|
|
394
410
|
</td>
|
|
395
411
|
<td class="availableToBorrow">
|
|
396
412
|
<label><input type="radio" name="borrow" value="available_to_borrow" />available_to_borrow</label>
|
|
@@ -410,6 +426,26 @@
|
|
|
410
426
|
font-weight: bold; display: none" name="purchase" value="Reflect" />
|
|
411
427
|
</td>
|
|
412
428
|
</tr>
|
|
429
|
+
<tr>
|
|
430
|
+
<td>
|
|
431
|
+
<fieldset style="margin-top: 10px;">
|
|
432
|
+
<legend style="color: black;">controls for browsed book</legend>
|
|
433
|
+
<table aria-hidden="true">
|
|
434
|
+
<tbody><tr>
|
|
435
|
+
<td class="action-button">
|
|
436
|
+
<button id="show_warning_modal">When Browsing (`user_has_browsed`),<br> show Warning Modal</button>
|
|
437
|
+
</td>
|
|
438
|
+
<td class="action-button">
|
|
439
|
+
<button id="show_expired_modal">While Browsing (`user_has_browsed`),<br> Expire book & show its modal</button>
|
|
440
|
+
</td>
|
|
441
|
+
<td class="action-button">
|
|
442
|
+
<button id="resync_timer">While Browsing (`user_has_browsed`),<br> resync timer</button>
|
|
443
|
+
</td>
|
|
444
|
+
</tr>
|
|
445
|
+
</tbody></table>
|
|
446
|
+
</fieldset>
|
|
447
|
+
</td>
|
|
448
|
+
</tr>
|
|
413
449
|
</table>
|
|
414
450
|
</fieldset>
|
|
415
451
|
</div>
|
package/index.html
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
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: 100px;
|
|
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
|
+
fieldset {
|
|
76
|
+
display: inline-grid;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.action-button button {
|
|
80
|
+
padding: 6px;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
border: 2px solid #194880;
|
|
83
|
+
border-radius: 10px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
body.modal-manager-open {
|
|
87
|
+
overflow: hidden;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
modal-manager[mode='closed'] {
|
|
91
|
+
display: none;
|
|
92
|
+
}
|
|
93
|
+
</style>
|
|
94
|
+
</head>
|
|
95
|
+
|
|
96
|
+
<body>
|
|
97
|
+
<ia-book-actions></ia-book-actions>
|
|
98
|
+
|
|
99
|
+
<script type="module">
|
|
100
|
+
/* eslint-disable */
|
|
101
|
+
|
|
102
|
+
import './src/ia-book-actions.js';
|
|
103
|
+
import {
|
|
104
|
+
defaultLendingStatus,
|
|
105
|
+
canBrowseAndBorrow,
|
|
106
|
+
} from './src/assets/data/lending-get-status-service.js';
|
|
107
|
+
import { ModalConfig } from '@internetarchive/modal-manager';
|
|
108
|
+
import { LocalCache } from '@internetarchive/local-cache';
|
|
109
|
+
|
|
110
|
+
const localCache = new LocalCache({
|
|
111
|
+
namespace: 'loanRenew',
|
|
112
|
+
defaultTTL: 1 * 60, // 1 minute
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const userid = '@neeraj-archive';
|
|
116
|
+
const identifier = 'naturalhistoryof00unse_4111';
|
|
117
|
+
let bwbPurchaseUrl = 'https://www.betterworldbooks.com/product/detail/cambridge-ancient-hist-v04-0521044863';
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
const modalConfig = new ModalConfig();
|
|
121
|
+
modalConfig.headerColor = '#d9534f';
|
|
122
|
+
|
|
123
|
+
let lendingBarPostInit = function lendingBarPostInit() {
|
|
124
|
+
setTimeout(function() {}, 100);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// set defaultLendingStatus for unavailable (without borrowables) book
|
|
128
|
+
let iaBookActions = document.querySelector('ia-book-actions');
|
|
129
|
+
|
|
130
|
+
iaBookActions.userid = userid;
|
|
131
|
+
iaBookActions.identifier = identifier;
|
|
132
|
+
iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
|
|
133
|
+
iaBookActions.lendingStatus = canBrowseAndBorrow;
|
|
134
|
+
iaBookActions.bwbPurchaseUrl = '';
|
|
135
|
+
iaBookActions.modalConfig = modalConfig;
|
|
136
|
+
iaBookActions.lendingBarPostInit = lendingBarPostInit;
|
|
137
|
+
iaBookActions.tokenDelay = 10; // 2 seconds
|
|
138
|
+
iaBookActions.timerExecutionSeconds = 3 // 4 seconds
|
|
139
|
+
iaBookActions.returnUrl = '';
|
|
140
|
+
iaBookActions.localCache = localCache;
|
|
141
|
+
|
|
142
|
+
let loanTotalTime2Min = { loanTotalTime: 120, loanRenewAtLast: 110, pageChangedInLast: 30 };
|
|
143
|
+
let loanTotalTime5Min = { loanTotalTime: 300, loanRenewAtLast: 240, pageChangedInLast: 60 };
|
|
144
|
+
let loanTotalTime10Min = { loanTotalTime: 600, loanRenewAtLast: 480, pageChangedInLast: 120 };
|
|
145
|
+
let loanTotalTime30Min = { loanTotalTime: 1800, loanRenewAtLast: 1500, pageChangedInLast: 600 };
|
|
146
|
+
let loanTotalTime1Hour = { loanTotalTime: 3600, loanRenewAtLast: 660, pageChangedInLast: 900 };
|
|
147
|
+
|
|
148
|
+
iaBookActions.loanRenewTimeConfig = loanTotalTime2Min;
|
|
149
|
+
let params = new URLSearchParams(document.location.search);
|
|
150
|
+
switch (params.get("timer")) {
|
|
151
|
+
case '5':
|
|
152
|
+
iaBookActions.loanRenewTimeConfig = loanTotalTime5Min;
|
|
153
|
+
break;
|
|
154
|
+
case '10':
|
|
155
|
+
iaBookActions.loanRenewTimeConfig = loanTotalTime10Min;
|
|
156
|
+
break;
|
|
157
|
+
case '30':
|
|
158
|
+
iaBookActions.loanRenewTimeConfig = loanTotalTime30Min;
|
|
159
|
+
break;
|
|
160
|
+
case '60':
|
|
161
|
+
iaBookActions.loanRenewTimeConfig = loanTotalTime1Hour;
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
iaBookActions.loanRenewTimeConfig = loanTotalTime2Min;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let lendingStatus1 = iaBookActions.lendingStatus;
|
|
169
|
+
let secondsLeftOnLoan = iaBookActions.loanRenewTimeConfig.loanTotalTime;
|
|
170
|
+
|
|
171
|
+
document.querySelectorAll('.titleBar input[type=checkbox]').forEach((item) => {
|
|
172
|
+
item.addEventListener('click', (e) => {
|
|
173
|
+
if (e.target.checked) {
|
|
174
|
+
iaBookActions.barType = 'title';
|
|
175
|
+
} else {
|
|
176
|
+
iaBookActions.barType = 'action';
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
document.querySelectorAll('.searchParam input[type=checkbox]').forEach((item) => {
|
|
182
|
+
item.addEventListener('click', (e) => {
|
|
183
|
+
var searchParams = new URLSearchParams(window.location.search);
|
|
184
|
+
var separate = '';
|
|
185
|
+
if (e.target.checked) {
|
|
186
|
+
separate = '?';
|
|
187
|
+
searchParams.set('q', 'test');
|
|
188
|
+
} else {
|
|
189
|
+
separate = '';
|
|
190
|
+
searchParams.delete('q');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (history.pushState) {
|
|
194
|
+
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + separate + searchParams;
|
|
195
|
+
window.history.pushState({path:newurl},'',newurl);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
document.querySelectorAll('.errorEnable input[type=checkbox]').forEach((item) => {
|
|
201
|
+
if (window.location.href.indexOf('?error=true') !== -1) {
|
|
202
|
+
item.checked = true;
|
|
203
|
+
}
|
|
204
|
+
item.addEventListener('click', (e) => {
|
|
205
|
+
var searchParams = new URLSearchParams(window.location.search);
|
|
206
|
+
var separate = '';
|
|
207
|
+
if (e.target.checked) {
|
|
208
|
+
separate = '?';
|
|
209
|
+
searchParams.set('error', true);
|
|
210
|
+
} else {
|
|
211
|
+
separate = '';
|
|
212
|
+
searchParams.delete('error');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (history.pushState) {
|
|
216
|
+
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + separate + searchParams;
|
|
217
|
+
window.history.pushState({path:newurl},'',newurl);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
document.querySelectorAll('.userState input[type=checkbox]').forEach((item) => {
|
|
224
|
+
item.addEventListener('click', (e) => {
|
|
225
|
+
if (e.target.checked) {
|
|
226
|
+
if (e.target.value === 'isAdmin') lendingStatus1.isAdmin = true;
|
|
227
|
+
if (e.target.value === 'isLoggedIn') iaBookActions.userid = '@neeraj';
|
|
228
|
+
} else {
|
|
229
|
+
if (e.target.value === 'isAdmin') lendingStatus1.isAdmin = false;
|
|
230
|
+
if (e.target.value === 'isLoggedIn') iaBookActions.userid = '';
|
|
231
|
+
}
|
|
232
|
+
let lending = {...defaultLendingStatus, ...lendingStatus1};
|
|
233
|
+
iaBookActions.lendingStatus = lending;
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
document.querySelectorAll('.printDisabled input[type=checkbox]').forEach((item) => {
|
|
238
|
+
item.addEventListener('click', (e) => {
|
|
239
|
+
if (e.target.checked) {
|
|
240
|
+
if (e.target.value === 'is_printdisabled') lendingStatus1.is_printdisabled = true;
|
|
241
|
+
if (e.target.value === 'user_is_printdisabled') lendingStatus1.user_is_printdisabled = true;
|
|
242
|
+
} else {
|
|
243
|
+
if (e.target.value === 'is_printdisabled') lendingStatus1.is_printdisabled = false;
|
|
244
|
+
if (e.target.value === 'user_is_printdisabled') lendingStatus1.user_is_printdisabled = false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let lending = {...defaultLendingStatus, ...lendingStatus1};
|
|
248
|
+
iaBookActions.lendingStatus = lending;
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
document.querySelectorAll('.availableToBrowse input[type=radio]').forEach((item) => {
|
|
253
|
+
item.addEventListener('click', async (e) => {
|
|
254
|
+
if (e.target.value === 'user_has_browsed') {
|
|
255
|
+
lendingStatus1.user_has_browsed = true;
|
|
256
|
+
lendingStatus1.available_to_browse = false;
|
|
257
|
+
lendingStatus1.secondsLeftOnLoan = secondsLeftOnLoan;
|
|
258
|
+
lendingStatus1.browsingExpired = false;
|
|
259
|
+
|
|
260
|
+
const expireDate = new Date(
|
|
261
|
+
new Date().getTime() + iaBookActions.loanRenewTimeConfig.loanTotalTime * 1000
|
|
262
|
+
);
|
|
263
|
+
try {
|
|
264
|
+
// set a value
|
|
265
|
+
await localCache.set({
|
|
266
|
+
key: `${identifier}-loanTime`,
|
|
267
|
+
value: expireDate,
|
|
268
|
+
ttl: Number(iaBookActions.loanRenewTimeConfig.loanTotalTime),
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
await localCache.delete(`${identifier}-pageChangedTime`);
|
|
272
|
+
} catch (error) {}
|
|
273
|
+
|
|
274
|
+
} else if(e.target.value === 'browsingExpired') {
|
|
275
|
+
lendingStatus1.user_has_browsed = true;
|
|
276
|
+
lendingStatus1.available_to_browse = false;
|
|
277
|
+
lendingStatus1.secondsLeftOnLoan = 0;
|
|
278
|
+
lendingStatus1.browsingExpired = true;
|
|
279
|
+
} else if (e.target.value === 'available_to_browse') {
|
|
280
|
+
lendingStatus1.available_to_browse = true;
|
|
281
|
+
lendingStatus1.user_has_browsed = false;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// wait for a while
|
|
285
|
+
setTimeout(() => {
|
|
286
|
+
let lending = {...defaultLendingStatus, ...lendingStatus1};
|
|
287
|
+
iaBookActions.lendingStatus = lending;
|
|
288
|
+
}, 10);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
document.querySelector('#show_warning_modal').addEventListener('click', async () => {
|
|
293
|
+
if (!iaBookActions.lendingStatus.user_has_browsed) {
|
|
294
|
+
const newLendingStatus = { ...iaBookActions.lendingStatus, user_has_browsed: true };
|
|
295
|
+
iaBookActions.lendingStatus = newLendingStatus;
|
|
296
|
+
await iaBookActions.updateComplete;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
iaBookActions.showWarningModal();
|
|
300
|
+
|
|
301
|
+
if (iaBookActions.lendingStatus.user_has_browsed) {
|
|
302
|
+
iaBookActions.showWarningModal();
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
document.querySelector('#show_expired_modal').addEventListener('click', async () => {
|
|
307
|
+
if (!iaBookActions.lendingStatus.user_has_browsed) {
|
|
308
|
+
const newLendingStatus = { ...iaBookActions.lendingStatus, user_has_browsed: true };
|
|
309
|
+
iaBookActions.lendingStatus = newLendingStatus;
|
|
310
|
+
await iaBookActions.updateComplete;
|
|
311
|
+
}
|
|
312
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
313
|
+
|
|
314
|
+
iaBookActions.browseHasExpired();
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
document.querySelector('#resync_timer').addEventListener('click', async (e) => {
|
|
318
|
+
if (iaBookActions.lendingStatus.user_has_browsed) {
|
|
319
|
+
document.querySelector('ia-book-actions').dispatchEvent(
|
|
320
|
+
new Event('visibilitychange', {
|
|
321
|
+
detail: {},
|
|
322
|
+
bubbles: true,
|
|
323
|
+
composed: true,
|
|
324
|
+
})
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
document.querySelectorAll('.availableToBorrow input[type=radio]').forEach((item) => {
|
|
331
|
+
item.addEventListener('click', (e) => {
|
|
332
|
+
if (e.target.value === 'available_to_borrow') {
|
|
333
|
+
lendingStatus1.available_to_borrow = true;
|
|
334
|
+
lendingStatus1.user_on_waitlist = false;
|
|
335
|
+
lendingStatus1.available_to_waitlist = false;
|
|
336
|
+
lendingStatus1.user_has_borrowed = false;
|
|
337
|
+
} else if (e.target.value === 'user_can_claim_waitlist') {
|
|
338
|
+
lendingStatus1.available_to_borrow = true;
|
|
339
|
+
lendingStatus1.user_on_waitlist = true;
|
|
340
|
+
lendingStatus1.user_can_claim_waitlist = true;
|
|
341
|
+
lendingStatus1.user_has_borrowed = false;
|
|
342
|
+
lendingStatus1.available_to_waitlist = false;
|
|
343
|
+
} else if (e.target.value === 'user_on_waitlist') {
|
|
344
|
+
lendingStatus1.available_to_borrow = false;
|
|
345
|
+
lendingStatus1.user_on_waitlist = true;
|
|
346
|
+
lendingStatus1.available_to_waitlist = false;
|
|
347
|
+
lendingStatus1.user_has_borrowed = false;
|
|
348
|
+
} else if (e.target.value === 'available_to_waitlist') {
|
|
349
|
+
lendingStatus1.available_to_borrow = false;
|
|
350
|
+
lendingStatus1.user_on_waitlist = false;
|
|
351
|
+
lendingStatus1.available_to_waitlist = true;
|
|
352
|
+
lendingStatus1.user_has_borrowed = false;
|
|
353
|
+
} else if (e.target.value === 'user_has_borrowed') {
|
|
354
|
+
lendingStatus1.available_to_borrow = false;
|
|
355
|
+
lendingStatus1.user_on_waitlist = false;
|
|
356
|
+
lendingStatus1.available_to_waitlist = false;
|
|
357
|
+
lendingStatus1.user_has_borrowed = true;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
let lending = {...defaultLendingStatus, ...lendingStatus1};
|
|
361
|
+
iaBookActions.lendingStatus = lending;
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
document.querySelectorAll('.purchase input[type=checkbox]').forEach((item) => {
|
|
366
|
+
item.addEventListener('click', (e) => {
|
|
367
|
+
if (e.target.checked) {
|
|
368
|
+
bwbPurchaseUrl = 'https://www.google.com';
|
|
369
|
+
} else {
|
|
370
|
+
bwbPurchaseUrl = ''
|
|
371
|
+
}
|
|
372
|
+
iaBookActions.bwbPurchaseUrl = bwbPurchaseUrl;
|
|
373
|
+
})
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
document.querySelector('.pageChangedEvent').addEventListener('click', () => {
|
|
377
|
+
// dispatch event to say book page has flipped
|
|
378
|
+
document.querySelector('ia-book-actions').dispatchEvent(
|
|
379
|
+
new CustomEvent('BookReader:userAction', {
|
|
380
|
+
detail: {},
|
|
381
|
+
bubbles: true,
|
|
382
|
+
composed: true,
|
|
383
|
+
})
|
|
384
|
+
);
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
// listen for IABookReader:BrowsingHasExpired
|
|
388
|
+
window.addEventListener('IABookReader:BrowsingHasExpired', () => {
|
|
389
|
+
console.log('IABookReader:BrowsingHasExpired EVENT FIRED');
|
|
390
|
+
});
|
|
391
|
+
</script>
|
|
392
|
+
|
|
393
|
+
<div>
|
|
394
|
+
<fieldset>
|
|
395
|
+
<legend>Dev testing for book title bar</legend>
|
|
396
|
+
<table class="initial">
|
|
397
|
+
<tr>
|
|
398
|
+
<td class="titleBar">
|
|
399
|
+
<label><input type="checkbox" name="title" value="title" />Title Bar</label>
|
|
400
|
+
</td>
|
|
401
|
+
<td class="searchParam">
|
|
402
|
+
<label><input type="checkbox" name="search" value="Search Param" />Search Param</label>
|
|
403
|
+
</td>
|
|
404
|
+
<td>
|
|
405
|
+
<label class="ia-button"><button class="pageChangedEvent">Page Change Event</button></label>
|
|
406
|
+
</td>
|
|
407
|
+
</tr>
|
|
408
|
+
</table>
|
|
409
|
+
</fieldset>
|
|
410
|
+
|
|
411
|
+
<fieldset>
|
|
412
|
+
<legend>Dev testing for book action bar</legend>
|
|
413
|
+
<table class="initial">
|
|
414
|
+
<tr colspan='5'>
|
|
415
|
+
<td class="errorEnable"><label><input type="checkbox" name="errorEnable" value="errorEnable" />Do you want to see error response?</label></td>
|
|
416
|
+
</tr>
|
|
417
|
+
<tr>
|
|
418
|
+
<td class="userState">
|
|
419
|
+
<label><input type="checkbox" name="user" value="isAdmin" />isAdmin</label>
|
|
420
|
+
<label><input type="checkbox" name="user" value="isLoggedIn" />isLoggedIn</label>
|
|
421
|
+
</td>
|
|
422
|
+
<td class="printDisabled">
|
|
423
|
+
<label><input type="checkbox" name="is_printdisabled" value="is_printdisabled" />is_printdisabled</label>
|
|
424
|
+
<label><input type="checkbox" name="user_is_printdisabled" value="user_is_printdisabled" />user_is_printdisabled</label>
|
|
425
|
+
</td>
|
|
426
|
+
<td class="availableToBrowse">
|
|
427
|
+
<label><input type="radio" name="browse" value="available_to_browse" />available_to_browse</label>
|
|
428
|
+
<label><input type="radio" name="browse" value="user_has_browsed" />user_has_browsed</label>
|
|
429
|
+
<label><input type="radio" name="browse" value="browsingExpired" />browsingExpired</label>
|
|
430
|
+
</td>
|
|
431
|
+
<td class="availableToBorrow">
|
|
432
|
+
<label><input type="radio" name="borrow" value="available_to_borrow" />available_to_borrow</label>
|
|
433
|
+
<label><input type="radio" name="borrow" value="user_on_waitlist" />user_on_waitlist</label>
|
|
434
|
+
<label><input type="radio" name="borrow" value="user_can_claim_waitlist" />user_can_claim_waitlist</label>
|
|
435
|
+
<label><input type="radio" name="borrow" value="available_to_waitlist" />available_to_waitlist</label>
|
|
436
|
+
<label><input type="radio" name="borrow" value="user_has_borrowed" />user_has_borrowed</label>
|
|
437
|
+
</td>
|
|
438
|
+
<td class="purchase">
|
|
439
|
+
<label><input type="checkbox" name="purchase" value="purchase" />purchase</label>
|
|
440
|
+
</td>
|
|
441
|
+
|
|
442
|
+
<td class="reflect">
|
|
443
|
+
<input type="button" style="padding: 10px;
|
|
444
|
+
background: #194880;
|
|
445
|
+
color: white;
|
|
446
|
+
font-weight: bold; display: none" name="purchase" value="Reflect" />
|
|
447
|
+
</td>
|
|
448
|
+
</tr>
|
|
449
|
+
<tr>
|
|
450
|
+
<td>
|
|
451
|
+
<fieldset style="margin-top: 10px;">
|
|
452
|
+
<legend style="color: black;">controls for browsed book</legend>
|
|
453
|
+
<table aria-hidden="true">
|
|
454
|
+
<tbody><tr>
|
|
455
|
+
<td class="action-button">
|
|
456
|
+
<button id="show_warning_modal">When Browsing (`user_has_browsed`),<br> show Warning Modal</button>
|
|
457
|
+
</td>
|
|
458
|
+
<td class="action-button">
|
|
459
|
+
<button id="show_expired_modal">While Browsing (`user_has_browsed`),<br> Expire book & show its modal</button>
|
|
460
|
+
</td>
|
|
461
|
+
<td class="action-button">
|
|
462
|
+
<button id="resync_timer">While Browsing (`user_has_browsed`),<br> resync timer</button>
|
|
463
|
+
</td>
|
|
464
|
+
</tr>
|
|
465
|
+
</tbody></table>
|
|
466
|
+
</fieldset>
|
|
467
|
+
</td>
|
|
468
|
+
</tr>
|
|
469
|
+
</table>
|
|
470
|
+
</fieldset>
|
|
471
|
+
</div>
|
|
472
|
+
<modal-manager></modal-manager>
|
|
473
|
+
</body>
|
|
474
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@internetarchive/ia-book-actions",
|
|
3
|
-
"version": "1.1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Bookreader actions for borrowable book",
|
|
5
5
|
"author": "Internet Archive",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -11,11 +11,16 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"start": "web-dev-server",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
14
|
+
"prepare:ghpages": "rimraf ghpages && yarn run prepare && vite build",
|
|
15
|
+
"prepare": "rimraf dist && husky install",
|
|
16
|
+
"lint": "eslint --ext \"./src/*.js\",.html . --ignore-path .gitignore && prettier \"./src/*.js\" --check --ignore-path .gitignore",
|
|
17
|
+
"format": "eslint --ext \"./src/*.js\",.html . --fix --ignore-path .gitignore && prettier \"./src/*.js\" --write --ignore-path .gitignore",
|
|
16
18
|
"test": "yarn run lint && yarn test:fast",
|
|
17
|
-
"test:fast": "web-test-runner --coverage",
|
|
18
|
-
"test:watch": "web-test-runner --watch"
|
|
19
|
+
"test:fast": "web-test-runner --coverage --playwright --browsers chromium firefox webkit",
|
|
20
|
+
"test:watch": "web-test-runner --watch --playwright --browsers chromium firefox webkit",
|
|
21
|
+
"deploy": "yarn run deploy:run -e $(git branch --show-current)",
|
|
22
|
+
"deploy:run": "yarn run prepare:ghpages && touch ghpages/.nojekyll && yarn run deploy:gh",
|
|
23
|
+
"deploy:gh": "gh-pages -t -d ghpages -m \"Build for $(git log --pretty=format:\"%h %an %ai %s\" -n1) [skip ci]\""
|
|
19
24
|
},
|
|
20
25
|
"dependencies": {
|
|
21
26
|
"@internetarchive/icon-info": "^1.2.6",
|
|
@@ -38,10 +43,13 @@
|
|
|
38
43
|
"eslint-plugin-lit": "^1.3.0",
|
|
39
44
|
"eslint-plugin-lit-a11y": "^1.0.1",
|
|
40
45
|
"eslint-plugin-wc": "^1.3.0",
|
|
41
|
-
"
|
|
46
|
+
"gh-pages": "^4.0.0",
|
|
47
|
+
"husky": "^7.0.0",
|
|
42
48
|
"lint-staged": "^10.0.0",
|
|
43
49
|
"prettier": "^2.0.4",
|
|
44
|
-
"sinon": "^13.0.2"
|
|
50
|
+
"sinon": "^13.0.2",
|
|
51
|
+
"vite": "^2.9.9",
|
|
52
|
+
"rimraf": "^3.0.2"
|
|
45
53
|
},
|
|
46
54
|
"eslintConfig": {
|
|
47
55
|
"extends": [
|
|
@@ -118,7 +118,7 @@ export const canBrowseAndBorrow = {
|
|
|
118
118
|
loanStartDate: '2021-07-30 09:57:40',
|
|
119
119
|
loansUrl: '/details/@neeraj-archive?tab=loans#loans-on-loan',
|
|
120
120
|
maxLoans: 10,
|
|
121
|
-
secondsLeftOnLoan:
|
|
121
|
+
secondsLeftOnLoan: 0,
|
|
122
122
|
shouldProtectImages: true,
|
|
123
123
|
totalWaitlistCount: 0,
|
|
124
124
|
userHasBorrowed: false,
|
|
@@ -47,7 +47,7 @@ export default class TimerCountdown extends LitElement {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
render() {
|
|
50
|
-
const viewClass = this.displayTime ? 'view' : '
|
|
50
|
+
const viewClass = this.displayTime ? 'view' : 'hide';
|
|
51
51
|
return html`
|
|
52
52
|
<button
|
|
53
53
|
id="timer-counter"
|
|
@@ -57,7 +57,8 @@ export default class TimerCountdown extends LitElement {
|
|
|
57
57
|
}}
|
|
58
58
|
role="timer"
|
|
59
59
|
>
|
|
60
|
-
<span>${this.minutesLeftOnLoan}</span>
|
|
60
|
+
<span>${this.minutesLeftOnLoan} - </span>
|
|
61
|
+
<span class="second">${Number(this.secondsLeftOnLoan)}</span>
|
|
61
62
|
<span class="sr-only">${this.remainingTime} left</span>
|
|
62
63
|
</button>
|
|
63
64
|
`;
|
|
@@ -32,7 +32,12 @@ export default async function ActionsHandlerService(options) {
|
|
|
32
32
|
location?.href?.indexOf('?error=true') !== -1 &&
|
|
33
33
|
location?.hostname !== 'archive.org';
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
const testHostname = ['localhost', 'internetarchive.github.io'];
|
|
36
|
+
let isTest = false;
|
|
37
|
+
if (testHostname.includes(location.hostname)) {
|
|
38
|
+
isTest = true;
|
|
39
|
+
baseHost = location.href;
|
|
40
|
+
}
|
|
36
41
|
|
|
37
42
|
let formData = new FormData();
|
|
38
43
|
formData.append('action', option.action);
|
|
@@ -51,8 +56,8 @@ export default async function ActionsHandlerService(options) {
|
|
|
51
56
|
};
|
|
52
57
|
}
|
|
53
58
|
|
|
54
|
-
// return success response for
|
|
55
|
-
if (
|
|
59
|
+
// return success response for localhost server...
|
|
60
|
+
if (isTest) {
|
|
56
61
|
if (
|
|
57
62
|
option?.action == 'renew_loan' ||
|
|
58
63
|
option?.action == 'return_loan'
|
package/src/core/services/log.js
CHANGED
|
@@ -8,7 +8,8 @@ const log =
|
|
|
8
8
|
location.host.match(/^(www|cat)-[a-z0-9]+\.archive\.org$/) ||
|
|
9
9
|
location.host.match(/\.code\.archive\.org$/) ||
|
|
10
10
|
location.host.match(/\.dev\.archive\.org$/) ||
|
|
11
|
-
location.host.match(/^ia-petabox-/)
|
|
11
|
+
location.host.match(/^ia-petabox-/) ||
|
|
12
|
+
location.host.match(/^internetarchive/)
|
|
12
13
|
? // eslint-disable-next-line no-console
|
|
13
14
|
console.log.bind(console) // convenient, no? Stateless function
|
|
14
15
|
: () => {};
|
package/src/ia-book-actions.js
CHANGED
|
@@ -59,6 +59,7 @@ export default class IABookActions extends LitElement {
|
|
|
59
59
|
disableActionGroup: { type: Boolean },
|
|
60
60
|
modal: { Object },
|
|
61
61
|
tokenDelay: { type: Number },
|
|
62
|
+
timerExecutionSeconds: { type: Number },
|
|
62
63
|
localCache: { type: Object },
|
|
63
64
|
loanRenewTimeConfig: { type: Object },
|
|
64
65
|
loanRenewResult: { type: Object },
|
|
@@ -79,6 +80,7 @@ export default class IABookActions extends LitElement {
|
|
|
79
80
|
this.sharedObserver = undefined;
|
|
80
81
|
this.disableActionGroup = false;
|
|
81
82
|
this.tokenDelay = 120; // in seconds
|
|
83
|
+
this.timerExecutionSeconds = 30;
|
|
82
84
|
|
|
83
85
|
// private props
|
|
84
86
|
this.postInitComplete = false;
|
|
@@ -89,10 +91,7 @@ export default class IABookActions extends LitElement {
|
|
|
89
91
|
this.lendingOptions = {};
|
|
90
92
|
this.borrowType = null; // 'browsed'|'borrowed'
|
|
91
93
|
this.browseTimer = undefined; // timeout
|
|
92
|
-
this.
|
|
93
|
-
|
|
94
|
-
/** @deprecated */
|
|
95
|
-
this.toast = undefined;
|
|
94
|
+
this.timeWhenTimerStart = undefined;
|
|
96
95
|
|
|
97
96
|
/**
|
|
98
97
|
* when user click on [return the book] button on warning modal
|
|
@@ -117,7 +116,7 @@ export default class IABookActions extends LitElement {
|
|
|
117
116
|
* contains one hour auto-loan-renew response
|
|
118
117
|
*
|
|
119
118
|
* @type {object} loanRenewResult
|
|
120
|
-
* @property {string} texts - texts messages
|
|
119
|
+
* @property {string} texts - texts messages shows in modal
|
|
121
120
|
* @property {boolean} renewNow - key to determine if need to renew now
|
|
122
121
|
* @property {number} secondsLeft - seconds left in active loan
|
|
123
122
|
*/
|
|
@@ -128,10 +127,19 @@ export default class IABookActions extends LitElement {
|
|
|
128
127
|
// clear all intervals for lending system
|
|
129
128
|
window?.IALendingIntervals?.clearAll();
|
|
130
129
|
|
|
131
|
-
|
|
130
|
+
this.sentryCaptureMsg(sentryLogs.disconnectedCallback);
|
|
132
131
|
this.disconnectResizeObserver();
|
|
133
132
|
}
|
|
134
133
|
|
|
134
|
+
/**
|
|
135
|
+
* send log messages to sentry
|
|
136
|
+
* @param {string} msg
|
|
137
|
+
*/
|
|
138
|
+
sentryCaptureMsg(msg) {
|
|
139
|
+
log(window?.Sentry);
|
|
140
|
+
window?.Sentry?.captureMessage(msg);
|
|
141
|
+
}
|
|
142
|
+
|
|
135
143
|
firstUpdated() {
|
|
136
144
|
// bind auto loan renew events
|
|
137
145
|
this.bindLoanRenewEvents();
|
|
@@ -223,7 +231,7 @@ export default class IABookActions extends LitElement {
|
|
|
223
231
|
log('setupLendingToolbarActions > hasExpired --- ');
|
|
224
232
|
|
|
225
233
|
if (!this.tokenPoller) {
|
|
226
|
-
|
|
234
|
+
this.sentryCaptureMsg(sentryLogs.bookWasExpired);
|
|
227
235
|
}
|
|
228
236
|
window?.IALendingIntervals?.clearAll();
|
|
229
237
|
|
|
@@ -285,16 +293,36 @@ export default class IABookActions extends LitElement {
|
|
|
285
293
|
|
|
286
294
|
/**
|
|
287
295
|
* auto-renew interval may stale when tab is in background,
|
|
288
|
-
* so
|
|
296
|
+
* so when user open that tab again,
|
|
297
|
+
* the [visibilitychange] event can trigger timer to show relavent messages
|
|
289
298
|
*/
|
|
290
|
-
document.addEventListener(
|
|
299
|
+
document.addEventListener('visibilitychange', async () => {
|
|
291
300
|
if (!document.hidden) {
|
|
292
|
-
log(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
301
|
+
log(
|
|
302
|
+
'visibilitychange event execute:------------------ ',
|
|
303
|
+
new Date().getMinutes(),
|
|
304
|
+
new Date().getSeconds(),
|
|
305
|
+
this.borrowType
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
if (
|
|
309
|
+
this.borrowType === 'browsed' &&
|
|
310
|
+
this.lendingStatus.browsingExpired === false
|
|
311
|
+
) {
|
|
312
|
+
const loanTime = await this.localCache.get(
|
|
313
|
+
`${this.identifier}-loanTime`
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
// number of seconds left in current loan
|
|
317
|
+
const secondsLeft = Math.round((loanTime - new Date()) / 1000);
|
|
318
|
+
|
|
319
|
+
if (secondsLeft >= this.timerExecutionSeconds) {
|
|
320
|
+
this.loanStatusCheckInterval(Number(secondsLeft));
|
|
321
|
+
} else {
|
|
322
|
+
this.browseHasExpired();
|
|
323
|
+
this.disconnectedCallback();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
298
326
|
}
|
|
299
327
|
});
|
|
300
328
|
}
|
|
@@ -476,31 +504,6 @@ export default class IABookActions extends LitElement {
|
|
|
476
504
|
await this.modal?.showModal({ config, customModalContent });
|
|
477
505
|
}
|
|
478
506
|
|
|
479
|
-
/**
|
|
480
|
-
* @deprecated
|
|
481
|
-
* create / select the toast-template component on DOM
|
|
482
|
-
*
|
|
483
|
-
* @memberof IABookActions
|
|
484
|
-
*/
|
|
485
|
-
async useToastManager() {
|
|
486
|
-
if (!this.toast) {
|
|
487
|
-
this.toast = this.shadowRoot.querySelector('toast-template');
|
|
488
|
-
|
|
489
|
-
if (!this.toast) this.toast = document.createElement('toast-template');
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
await this.shadowRoot.appendChild(this.toast);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
/**
|
|
496
|
-
* @deprecated
|
|
497
|
-
* close/hide toast message
|
|
498
|
-
*/
|
|
499
|
-
async closeToastManager() {
|
|
500
|
-
this.toast = this.shadowRoot.querySelector('toast-template');
|
|
501
|
-
this.toast?.remove();
|
|
502
|
-
}
|
|
503
|
-
|
|
504
507
|
/**
|
|
505
508
|
* Execute when loan is expired
|
|
506
509
|
*/
|
|
@@ -526,7 +529,7 @@ export default class IABookActions extends LitElement {
|
|
|
526
529
|
|
|
527
530
|
await this.showExpiredModal();
|
|
528
531
|
|
|
529
|
-
|
|
532
|
+
this.sentryCaptureMsg(sentryLogs.browseHasExpired);
|
|
530
533
|
}
|
|
531
534
|
|
|
532
535
|
async startBrowseTimer() {
|
|
@@ -629,7 +632,10 @@ export default class IABookActions extends LitElement {
|
|
|
629
632
|
if (this.loanRenewResult.renewNow) {
|
|
630
633
|
// Now, let's reset loan duration & this.lendingStatus
|
|
631
634
|
const loanTime = await this.localCache.get(`${this.identifier}-loanTime`);
|
|
632
|
-
|
|
635
|
+
|
|
636
|
+
// number of seconds left in current loan
|
|
637
|
+
const secondsLeft = Math.round((loanTime - new Date()) / 1000);
|
|
638
|
+
log(loanTime, secondsLeft);
|
|
633
639
|
|
|
634
640
|
log('IABookActions: handleLoanAutoRenewed --- ', {
|
|
635
641
|
ajaxResponse: detail?.data,
|
|
@@ -649,7 +655,7 @@ export default class IABookActions extends LitElement {
|
|
|
649
655
|
this.modal?.closeModal();
|
|
650
656
|
this.modal.removeAttribute('id');
|
|
651
657
|
this.modal.customModalContent = nothing;
|
|
652
|
-
|
|
658
|
+
this.sentryCaptureMsg(sentryLogs.bookHasRenewed);
|
|
653
659
|
}
|
|
654
660
|
}
|
|
655
661
|
|
|
@@ -658,7 +664,7 @@ export default class IABookActions extends LitElement {
|
|
|
658
664
|
*
|
|
659
665
|
* @memberof IABookActions
|
|
660
666
|
*/
|
|
661
|
-
startTimerCountdown() {
|
|
667
|
+
async startTimerCountdown() {
|
|
662
668
|
window?.IALendingIntervals?.clearTimerCountdown();
|
|
663
669
|
|
|
664
670
|
const secondsLeft = Number(this.lendingStatus.secondsLeftOnLoan);
|
|
@@ -666,7 +672,7 @@ export default class IABookActions extends LitElement {
|
|
|
666
672
|
|
|
667
673
|
window.IALendingIntervals.timerCountdown = setInterval(async () => {
|
|
668
674
|
// interval execution block
|
|
669
|
-
await this.
|
|
675
|
+
await this.loanStatusCheckInterval(secondsLeft);
|
|
670
676
|
}, this.timerExecutionSeconds * 1000);
|
|
671
677
|
}
|
|
672
678
|
|
|
@@ -675,10 +681,10 @@ export default class IABookActions extends LitElement {
|
|
|
675
681
|
* - if setInterval timer gone off, let's resync
|
|
676
682
|
* - loan-renew attempt to renew the loan OR show relavant message
|
|
677
683
|
* - if loan has expired, clear interval timers
|
|
678
|
-
*
|
|
679
|
-
* @param {Number} secondsLeftOnLoan
|
|
684
|
+
*
|
|
685
|
+
* @param {Number} secondsLeftOnLoan
|
|
680
686
|
*/
|
|
681
|
-
async
|
|
687
|
+
async loanStatusCheckInterval(secondsLeftOnLoan) {
|
|
682
688
|
let secondsLeft = secondsLeftOnLoan;
|
|
683
689
|
secondsLeft -= this.timerExecutionSeconds;
|
|
684
690
|
secondsLeft = Math.round(secondsLeft); // round number
|
|
@@ -688,22 +694,30 @@ export default class IABookActions extends LitElement {
|
|
|
688
694
|
// if really updated, escape from here
|
|
689
695
|
const resyncd = await this.reSyncTimerIfGoneOff(secondsLeft);
|
|
690
696
|
|
|
691
|
-
if (resyncd
|
|
697
|
+
if (resyncd.hasSynced) {
|
|
692
698
|
secondsLeft = resyncd.whatShouldLeft;
|
|
693
|
-
|
|
694
699
|
log('startTimerCountdown --- stale, timer has resyncd', {
|
|
695
700
|
secondsLeft,
|
|
696
701
|
});
|
|
697
702
|
}
|
|
698
703
|
|
|
699
|
-
log(
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
+
log(
|
|
705
|
+
'startTimerCountdown --- countdown still valid. continue...',
|
|
706
|
+
{
|
|
707
|
+
resyncd,
|
|
708
|
+
secondsLeft,
|
|
709
|
+
loanRenewAtLast: this.loanRenewTimeConfig.loanRenewAtLast,
|
|
710
|
+
},
|
|
711
|
+
'time: ',
|
|
712
|
+
new Date().getMinutes(),
|
|
713
|
+
':',
|
|
714
|
+
new Date().getSeconds(),
|
|
715
|
+
', timerDelay: ',
|
|
716
|
+
this.timerExecutionSeconds
|
|
717
|
+
);
|
|
704
718
|
|
|
705
719
|
/**
|
|
706
|
-
* execute from last 10th
|
|
720
|
+
* execute from last 10th minutes to 0th minute
|
|
707
721
|
* - 10th - to check if user has viewed
|
|
708
722
|
* - till 0th - to show warning msg with remaining time to auto expired
|
|
709
723
|
* @see IABookActions::bindLoanRenewEvents
|
|
@@ -715,7 +729,7 @@ export default class IABookActions extends LitElement {
|
|
|
715
729
|
// clear interval in secondsLeft if less
|
|
716
730
|
if (secondsLeft <= this.timerExecutionSeconds) {
|
|
717
731
|
this.disconnectedCallback();
|
|
718
|
-
|
|
732
|
+
this.sentryCaptureMsg(sentryLogs.clearOneHourTimer);
|
|
719
733
|
}
|
|
720
734
|
}
|
|
721
735
|
|
|
@@ -723,8 +737,7 @@ export default class IABookActions extends LitElement {
|
|
|
723
737
|
* helper function to determine if timer is not in sync properly
|
|
724
738
|
*
|
|
725
739
|
* @param {number} timerSecondsLeft - actual seconds left get from setInterval
|
|
726
|
-
*
|
|
727
|
-
* @memberof TimerCountdown
|
|
740
|
+
* @returns {Object} { hasSynced: [boolean], whatShouldLeft: [number] }
|
|
728
741
|
*/
|
|
729
742
|
async reSyncTimerIfGoneOff(timerSecondsLeft) {
|
|
730
743
|
const currentTime = new Date();
|
|
@@ -736,6 +749,15 @@ export default class IABookActions extends LitElement {
|
|
|
736
749
|
const secondsShouldLeft =
|
|
737
750
|
this.lendingStatus.secondsLeftOnLoan - diffInSeconds;
|
|
738
751
|
|
|
752
|
+
log('currentTime: ', currentTime);
|
|
753
|
+
log('timeWhenTimerStart: ', this.timeWhenTimerStart);
|
|
754
|
+
log('diffInSeconds: ', diffInSeconds);
|
|
755
|
+
log('secondsShouldLeft: ', secondsShouldLeft);
|
|
756
|
+
log(
|
|
757
|
+
'this.lendingStatus.secondsLeftOnLoan: ',
|
|
758
|
+
this.lendingStatus.secondsLeftOnLoan
|
|
759
|
+
);
|
|
760
|
+
|
|
739
761
|
// convert in minutes
|
|
740
762
|
const whatIsleft = Math.round(timerSecondsLeft);
|
|
741
763
|
const whatShouldLeft = Math.round(secondsShouldLeft);
|
|
@@ -759,10 +781,10 @@ export default class IABookActions extends LitElement {
|
|
|
759
781
|
|
|
760
782
|
if (whatIsleft !== whatShouldLeft) {
|
|
761
783
|
log(`reSyncTimerIfGoneOff --- let's re-sync.`);
|
|
762
|
-
|
|
763
784
|
return { hasSynced: true, whatShouldLeft };
|
|
764
785
|
}
|
|
765
|
-
|
|
786
|
+
|
|
787
|
+
return { hasSynced: false, whatShouldLeft };
|
|
766
788
|
}
|
|
767
789
|
|
|
768
790
|
/**
|
|
@@ -981,12 +1003,6 @@ export default class IABookActions extends LitElement {
|
|
|
981
1003
|
justify-content: center;
|
|
982
1004
|
flex-wrap: wrap;
|
|
983
1005
|
}
|
|
984
|
-
|
|
985
|
-
toast-template {
|
|
986
|
-
--toastTopMargin: 80px;
|
|
987
|
-
--toastBGColor: #333;
|
|
988
|
-
--toastFontColor: #fff;
|
|
989
|
-
}
|
|
990
1006
|
`;
|
|
991
1007
|
}
|
|
992
1008
|
}
|
|
@@ -13,7 +13,9 @@ const container = ({
|
|
|
13
13
|
.loanRenewAtLast=${loanRenewAtLast}
|
|
14
14
|
></timer-countdown>`;
|
|
15
15
|
|
|
16
|
-
describe('<timer-countdown>', () => {
|
|
16
|
+
describe('<timer-countdown>', async () => {
|
|
17
|
+
await aTimeout(5000);
|
|
18
|
+
|
|
17
19
|
it('timer interval is undefined when loan is expired', async () => {
|
|
18
20
|
const el = await fixture(
|
|
19
21
|
container({
|
|
@@ -36,7 +38,6 @@ describe('<timer-countdown>', () => {
|
|
|
36
38
|
})
|
|
37
39
|
);
|
|
38
40
|
|
|
39
|
-
await aTimeout(1900);
|
|
40
41
|
await el.updateComplete;
|
|
41
42
|
|
|
42
43
|
expect(el.secondsLeftOnLoan).to.equal(2);
|
|
@@ -376,7 +376,8 @@ describe('Browsing expired status', () => {
|
|
|
376
376
|
});
|
|
377
377
|
});
|
|
378
378
|
|
|
379
|
-
describe('Auto renew one hour loan', () => {
|
|
379
|
+
describe('Auto renew one hour loan', async () => {
|
|
380
|
+
await aTimeout(5000);
|
|
380
381
|
it('Book is browsing and renewed it now', async () => {
|
|
381
382
|
const loanTime = 88;
|
|
382
383
|
const el = await fixture(
|
|
@@ -449,6 +450,61 @@ describe('Auto renew one hour loan', () => {
|
|
|
449
450
|
});
|
|
450
451
|
});
|
|
451
452
|
|
|
453
|
+
describe('Visibility change API for document', async () => {
|
|
454
|
+
await aTimeout(5000);
|
|
455
|
+
|
|
456
|
+
beforeEach(() => {
|
|
457
|
+
Object.defineProperty(document, 'hidden', {
|
|
458
|
+
value: false,
|
|
459
|
+
configurable: true,
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
afterEach(() => {
|
|
464
|
+
Object.defineProperty(document, 'hidden', {
|
|
465
|
+
value: true,
|
|
466
|
+
configurable: true,
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it('when book is not expired', async () => {
|
|
471
|
+
const el = await fixture(
|
|
472
|
+
container({
|
|
473
|
+
userid: '@user1',
|
|
474
|
+
identifier: 'foobar',
|
|
475
|
+
lendingStatus: {
|
|
476
|
+
user_has_browsed: true,
|
|
477
|
+
browsingExpired: false,
|
|
478
|
+
},
|
|
479
|
+
})
|
|
480
|
+
);
|
|
481
|
+
await el.updateComplete;
|
|
482
|
+
|
|
483
|
+
const spy = Sinon.spy(el, 'loanStatusCheckInterval');
|
|
484
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
485
|
+
|
|
486
|
+
expect(spy.calledOnce).to.be.true;
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it('when book is already expired', async () => {
|
|
490
|
+
const el = await fixture(
|
|
491
|
+
container({
|
|
492
|
+
userid: '@user1',
|
|
493
|
+
identifier: 'foobar',
|
|
494
|
+
lendingStatus: {
|
|
495
|
+
user_has_browsed: true,
|
|
496
|
+
},
|
|
497
|
+
})
|
|
498
|
+
);
|
|
499
|
+
await el.updateComplete;
|
|
500
|
+
|
|
501
|
+
const spy = Sinon.spy(el, 'browseHasExpired');
|
|
502
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
503
|
+
|
|
504
|
+
expect(spy.calledOnce).to.be.true;
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
|
|
452
508
|
describe('Shared Resize Observer', () => {
|
|
453
509
|
it('can receive a Shared Resize Observer', async () => {
|
|
454
510
|
const sharedObserverStub = new SharedResizeObserver();
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
|
|
4
|
+
// https://vitejs.dev/config/
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
base: '',
|
|
7
|
+
build: {
|
|
8
|
+
outDir: 'ghpages',
|
|
9
|
+
manifest: true,
|
|
10
|
+
rollupOptions: {
|
|
11
|
+
input: {
|
|
12
|
+
main: resolve(__dirname, 'index.html'),
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
server: {
|
|
17
|
+
host: true,
|
|
18
|
+
port: 8080,
|
|
19
|
+
open: true,
|
|
20
|
+
cors: true,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
@@ -5,7 +5,7 @@ const hmr = process.argv.includes('--hmr');
|
|
|
5
5
|
|
|
6
6
|
export default /** @type {import('@web/dev-server').DevServerConfig} */ ({
|
|
7
7
|
nodeResolve: true,
|
|
8
|
-
open: '/
|
|
8
|
+
open: '/',
|
|
9
9
|
watch: !hmr,
|
|
10
10
|
|
|
11
11
|
/** Compile JS for older browsers. Requires @web/dev-server-esbuild plugin */
|