@internetarchive/ia-book-actions 0.0.29 → 0.1.1

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.
@@ -0,0 +1,86 @@
1
+ import { expect, aTimeout } from '@open-wc/testing';
2
+
3
+ import { LocalCache } from '@internetarchive/local-cache';
4
+ import { LoanRenewHelper } from '../../../src/core/services/loan-renew-helper.js';
5
+
6
+ const identifier = 'booBar';
7
+ const loanRenewTimeConfig = {
8
+ loanTotalTime: 13,
9
+ loanRenewAtLast: 10,
10
+ pageChangedInLast: 12,
11
+ };
12
+
13
+ // localCache used for auto-loan-renew
14
+ const localCache = new LocalCache({
15
+ namespace: 'loanRenew',
16
+ });
17
+
18
+ beforeEach(async () => {
19
+ await localCache.set({
20
+ key: `${identifier}-loanTime`,
21
+ value: new Date(
22
+ new Date().getTime() + loanRenewTimeConfig.loanTotalTime * 1000
23
+ ),
24
+ ttl: Number(loanRenewTimeConfig.loanTotalTime),
25
+ });
26
+ });
27
+
28
+ describe('Loan Renew Determine', () => {
29
+ it('flip book page while reading a book', async () => {
30
+ await aTimeout(1500);
31
+
32
+ await localCache.set({
33
+ key: `${identifier}-pageChangedTime`,
34
+ value: new Date(), // current time
35
+ ttl: Number(loanRenewTimeConfig.loanTotalTime),
36
+ });
37
+
38
+ const loanRenewHelper = new LoanRenewHelper(
39
+ true, // hasPageChanged
40
+ identifier,
41
+ localCache,
42
+ loanRenewTimeConfig
43
+ );
44
+ await loanRenewHelper.handleLoanRenew();
45
+
46
+ expect(loanRenewHelper.result.renewNow).to.be.false;
47
+ });
48
+
49
+ it('auto renewed book when user is currently reading', async () => {
50
+ await localCache.set({
51
+ key: `${identifier}-pageChangedTime`,
52
+ value: new Date(), // current time
53
+ ttl: Number(loanRenewTimeConfig.loanTotalTime),
54
+ });
55
+
56
+ await aTimeout(1500);
57
+
58
+ const loanRenewHelper = new LoanRenewHelper(
59
+ false, // timer-countdown event
60
+ identifier,
61
+ localCache,
62
+ loanRenewTimeConfig
63
+ );
64
+ await loanRenewHelper.handleLoanRenew();
65
+
66
+ expect(loanRenewHelper.result.renewNow).to.be.true;
67
+ });
68
+
69
+ it('get toast message template', async () => {
70
+ const loanRenewHelper = new LoanRenewHelper(
71
+ false,
72
+ identifier,
73
+ localCache,
74
+ loanRenewTimeConfig
75
+ );
76
+
77
+ const toastMsg = loanRenewHelper.getMessageTexts(
78
+ loanRenewHelper.loanReturnWarning,
79
+ '65' // in seconds
80
+ );
81
+
82
+ expect(toastMsg).to.be.equal(
83
+ 'This book will be automatically returned in 2 minutes unless you turn a page.'
84
+ );
85
+ });
86
+ });
@@ -4,11 +4,17 @@ import '../src/ia-book-actions.js';
4
4
  import Sinon from 'sinon';
5
5
 
6
6
  import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
7
+ import { LocalCache } from '@internetarchive/local-cache';
7
8
 
8
9
  afterEach(() => {
9
10
  Sinon.restore();
10
11
  });
11
12
 
13
+ // localCache used for auto-loan-renew
14
+ const localCache = new LocalCache({
15
+ namespace: 'loanRenew',
16
+ });
17
+
12
18
  const container = ({ userid, identifier, lendingStatus = {} } = {}) =>
13
19
  html`<ia-book-actions
14
20
  .userid=${userid}
@@ -81,7 +87,7 @@ describe('Primary Actions data', () => {
81
87
  );
82
88
  const expectedPrimaryActions = [
83
89
  {
84
- text: 'Borrow for 1 hour',
90
+ text: 'Borrow', // changed from 'Borrow for 1 hour'
85
91
  callback: () => {},
86
92
  className: 'ia-button primary',
87
93
  },
@@ -161,7 +167,7 @@ describe('Borrow status actions', () => {
161
167
 
162
168
  // removed available_to_borrow from lending bar
163
169
  expect(el.lendingStatus.available_to_borrow).to.be.false;
164
- expect(el.primaryActions[0].text).to.equal('Borrow for 1 hour');
170
+ expect(el.primaryActions[0].text).to.equal('Borrow');
165
171
  });
166
172
 
167
173
  it('Check action for borrowable book without user', async () => {
@@ -182,9 +188,7 @@ describe('Borrow status actions', () => {
182
188
  },
183
189
  ];
184
190
 
185
- expect(el.primaryTitle).to.equal(
186
- 'Renewable every hour, pending availability.'
187
- );
191
+ expect(el.primaryTitle).to.equal('');
188
192
  expect(el.primaryActions.length).to.equal(2);
189
193
  expect(el.primaryActions[0].text).to.equal('Log In and Borrow');
190
194
  expect(el.primaryActions[0].text).to.equal(expectedPrimaryActions[0].text);
@@ -232,9 +236,14 @@ describe('Browsing expired status', () => {
232
236
  },
233
237
  })
234
238
  );
235
- expect(el.primaryTitle).contains('Borrow ends at ');
239
+ expect(el.primaryTitle).contains('');
236
240
  expect(el.primaryActions[0].text).to.equal('Return now');
237
241
  expect(el.primaryActions[1].text).to.equal('Print Disability Access');
242
+
243
+ // default params of one-hour loan renew
244
+ expect(el.loanRenewResult.texts).to.equal('');
245
+ expect(el.loanRenewResult.renewNow).to.equal(false);
246
+ expect(el.loanRenewResult.secondsLeft).to.equal(0);
238
247
  });
239
248
 
240
249
  it('Book is browsing and going to expire after 1 second', async () => {
@@ -250,11 +259,23 @@ describe('Browsing expired status', () => {
250
259
  })
251
260
  );
252
261
 
262
+ // timer-countdown is still active
263
+ expect(el.shadowRoot.querySelector('timer-countdown')).to.not.be.null;
264
+
253
265
  await aTimeout(1500); // wait for 1.5 second
254
266
  await el.updateComplete;
255
267
 
256
- expect(el.primaryTitle).contains('Your loan has expired.');
257
- expect(el.primaryActions[0].text).to.equal('Borrow again');
268
+ expect(el.primaryActions[0].text).to.equal('Borrow');
269
+
270
+ // timer-countdown is gone now
271
+ expect(el.shadowRoot.querySelector('timer-countdown')).to.be.null;
272
+
273
+ // // book has been expired
274
+ expect(el.loanRenewResult.renewNow).to.equal(false);
275
+ expect(el.loanRenewResult.secondsLeft).to.equal(0);
276
+ expect(el.loanRenewResult.texts).to.equal(
277
+ 'This book has been automatically returned due to inactivity.'
278
+ );
258
279
  });
259
280
 
260
281
  it('Expiring book cancels interval & emits event', async () => {
@@ -279,9 +300,8 @@ describe('Browsing expired status', () => {
279
300
  el.lendingStatus = browsingStatus;
280
301
  await el.updateComplete;
281
302
 
282
- expect(el.primaryTitle).contains('Borrow ends at ');
303
+ expect(el.primaryTitle).contains('');
283
304
  expect(el.primaryActions[0].text).to.equal('Return now');
284
- expect(el.tokenPoller.loanTokenInterval).to.not.equal(undefined);
285
305
 
286
306
  const expiredStatus = { ...browsingStatus, browsingExpired: true };
287
307
  el.lendingStatus = expiredStatus;
@@ -289,12 +309,55 @@ describe('Browsing expired status', () => {
289
309
  await aTimeout(1500); // wait for 1.5 sec
290
310
 
291
311
  expect(eventReceived).to.equal(true);
292
- expect(el.primaryTitle).contains('Your loan has expired.');
293
- expect(el.primaryActions[0].text).to.equal('Borrow again');
312
+ expect(el.primaryActions[0].text).to.equal('Borrow');
294
313
  expect(el.tokenPoller.loanTokenInterval).to.equal(undefined);
295
314
  });
296
315
  });
297
316
 
317
+ describe('Auto renew one hour loan', () => {
318
+ it('Book is browsing and renewed it now', async () => {
319
+ const el = await fixture(
320
+ container({
321
+ userid: '@userid',
322
+ identifier: 'Foo',
323
+ lendingStatus: {
324
+ is_lendable: true,
325
+ user_has_browsed: true,
326
+ browseHasExpired: false,
327
+ secondsLeftOnLoan: 12,
328
+ },
329
+ })
330
+ );
331
+
332
+ el.loanRenewResult = {
333
+ texts: 'This book has been renewed for 1 hour.',
334
+ renewNow: true,
335
+ secondsLeft: 10,
336
+ };
337
+
338
+ await localCache.set({
339
+ key: `${el.identifier}-loanTime`,
340
+ value: new Date(new Date().getTime() + 10 * 1000),
341
+ ttl: Number(10),
342
+ });
343
+
344
+ const myEvent = new CustomEvent('loanAutoRenewed');
345
+ el.addEventListener('loanAutoRenewed', () => {
346
+ el.handleLoanAutoRenewed();
347
+ });
348
+ el.dispatchEvent(myEvent);
349
+
350
+ await aTimeout(1500); // wait for 1.5 second
351
+ await el.updateComplete;
352
+
353
+ expect(el.loanRenewResult.texts).to.equal(
354
+ 'This book has been renewed for 1 hour.'
355
+ );
356
+ expect(el.loanRenewResult.renewNow).to.equal(true);
357
+ expect(el.loanRenewResult.secondsLeft).to.equal(10);
358
+ });
359
+ });
360
+
298
361
  describe('Shared Resize Observer', () => {
299
362
  it('can receive a Shared Resize Observer', async () => {
300
363
  const sharedObserverStub = new SharedResizeObserver();
@@ -1,146 +0,0 @@
1
- <!doctype html>
2
- <html lang="en-GB">
3
-
4
- <head>
5
- <meta charset="utf-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
7
- <style>
8
- html {
9
- font-size: 10px;
10
- /* This is to match petabox's base font size */
11
- }
12
- body {
13
- margin: 0;
14
- text-align: center;
15
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
16
- }
17
- #demo {
18
- height: 50px;
19
- }
20
- ia-book-actions {
21
- --white: #fff;
22
- --black: #000;
23
- --primaryBGColor: var(--black);
24
- --secondaryBGColor: #222;
25
- --tertiaryBGColor: #333;
26
- --primaryTextColor: var(--white);
27
- --primaryCTAFill: #194880;
28
- --primaryCTABorder: #c5d1df;
29
- --secondaryCTAFill: #333;
30
- --secondaryCTABorder: #999;
31
- --secondaryCTAFillRGB: 51, 51, 51;
32
- --primaryErrorCTAFill: #e51c26;
33
- --primaryErrorCTABorder: #f8c6c8;
34
- --primaryCTAFillRGB: 25, 72, 128;
35
- --primaryErrorCTAFillRGB: 229, 28, 38;
36
- --primaryDisableCTAFill: #767676;
37
- }
38
-
39
- fieldset {
40
- width: fit-content;
41
- margin-top: 50px;
42
- }
43
- fieldset legend {
44
- text-align: left;
45
- font-size: 12px;
46
- }
47
- td {
48
- color: white;
49
- font-size: 14px;
50
- border-radius: 5%;
51
- display: table-cell;
52
- text-align: initial;
53
- margin: 5px 0;
54
- width: max-content;
55
- display: block;
56
- }
57
- label {
58
- padding: 10px;
59
- display: block;
60
- cursor: pointer;
61
- margin: 2px;
62
- background: #4e545a;
63
- border-radius: 10px;
64
- }
65
- input[type="radio"], input[type="checkbox"] {
66
- margin-top: 0;
67
- vertical-align: middle;
68
- }
69
-
70
- .initial td {
71
- float: left;
72
- margin: 2px;
73
- }
74
-
75
- body.modal-manager-open {
76
- overflow: hidden;
77
- }
78
-
79
- modal-manager[mode='closed'] {
80
- display: none;
81
- }
82
- </style>
83
- </head>
84
-
85
- <body>
86
- <ia-bookreader class="focus-on-child-only" signedin="" fullscreen="">
87
- <div slot="header">
88
- <ia-book-actions></ia-book-actions>
89
- </div>
90
- <div slot="main">
91
- <div id="BookReader"></div>
92
- </div>
93
- </ia-bookreader>
94
-
95
-
96
- <script type="module">
97
- /* eslint-disable */
98
- import '@internetarchive/bookreader';
99
- import '@internetarchive/bookreader/BookReader/jquery-1.10.1.js';
100
- import '@internetarchive/bookreader/BookReader/BookReader.js';
101
- import '../src/ia-book-actions.js';
102
- import {
103
- defaultLendingStatus,
104
- canBrowseAndBorrow,
105
- } from '../src/assets/data/lending-get-status-service.js';
106
- import { ModalConfig } from '@internetarchive/modal-manager';
107
-
108
- const userid = '@neeraj-archive';
109
- const identifier = 'naturalhistoryof00unse_4111';
110
- let bwbPurchaseUrl = 'https://www.betterworldbooks.com/product/detail/cambridge-ancient-hist-v04-0521044863';
111
-
112
- let iaBookActions = document.querySelector('ia-book-actions');
113
-
114
- // for debugging
115
- window.iaBookActions = iaBookActions;
116
-
117
- const modalConfig = new ModalConfig();
118
- modalConfig.headerColor = '#d9534f';
119
-
120
- let lendingBarPostInit = function lendingBarPostInit() {
121
- setTimeout(function() {
122
- console.log('executed', 'br.init()');
123
- }, 100);
124
- }
125
-
126
- // set defaultLendingStatus for unavailable (without borrowables) book
127
- iaBookActions.userid = userid;
128
- iaBookActions.identifier = identifier;
129
- iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
130
- iaBookActions.lendingStatus = canBrowseAndBorrow;
131
- iaBookActions.bwbPurchaseUrl = '';
132
- iaBookActions.modalConfig = modalConfig;
133
- iaBookActions.lendingBarPostInit = lendingBarPostInit;
134
- iaBookActions.tokenDelay = 2000; // 2 seconds
135
- iaBookActions.returnUrl = 'https://openlibrary.org';
136
-
137
- let lendingStatus1 = iaBookActions.lendingStatus;
138
-
139
- const manifest = await fetch('https://ia801302.us.archive.org/BookReader/BookReaderJSIA.php?id=goody&itemPath=/29/items/goody&server=ia801302.us.archive.org&format=jsonp&subPrefix=goody&requestUri=/details/goody/mode/1up%3Fview%3Dtheater%26ui%3Dembed%26wrapper%3Dfalse');
140
-
141
- console.log('manifest ****', manifest).then(res => res.json());
142
- </script>
143
-
144
- </div>
145
- </body>
146
- </html>