@internetarchive/ia-book-actions 0.0.29-alpha2 → 0.0.29-alpha21

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 CHANGED
@@ -15,7 +15,7 @@
15
15
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
16
16
  }
17
17
  #demo {
18
- height: 50px;
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: '1HourLoanStorage',
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.autoRenewTimeConfig = {
131
- totalTime: 60, // 60 second = 1 min
132
- autoCheckAt: 55, // totalTime - 10th minute
133
- FlippedInLast: 15, // within last 15 second/minute
129
+ iaBookActions.loanRenewConfig = {
130
+ totalTime: 20, // 60 second = 1 min
131
+ autoCheckAt: 15, // totalTime - 10th minute
132
+ pageChangedInLast: 15, // within last 15 second/minute
134
133
  };
135
134
 
136
135
  let lendingStatus1 = iaBookActions.lendingStatus;
137
- let secondsLeftOnLoan = 60;
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: parseInt(iaBookActions.autoRenewTimeConfig.totalTime),
230
- })
213
+ ttl: Number(iaBookActions.loanRenewConfig.totalTime),
214
+ });
231
215
 
232
- await localCache.delete(`${identifier}-pageFlipTime`);
216
+ await localCache.delete(`${identifier}-pageChangedTime`);
233
217
  } catch (error) {}
234
218
 
235
219
  } else if(e.target.value === 'browsingExpired') {
@@ -242,8 +226,11 @@
242
226
  lendingStatus1.user_has_browsed = false;
243
227
  }
244
228
 
245
- let lending = {...defaultLendingStatus, ...lendingStatus1};
246
- iaBookActions.lendingStatus = lending;
229
+ // wait for a while
230
+ setTimeout(() => {
231
+ let lending = {...defaultLendingStatus, ...lendingStatus1};
232
+ iaBookActions.lendingStatus = lending;
233
+ }, 10);
247
234
  });
248
235
  });
249
236
 
@@ -292,6 +279,17 @@
292
279
  iaBookActions.bwbPurchaseUrl = bwbPurchaseUrl;
293
280
  })
294
281
  });
282
+
283
+ document.querySelector('.pageChangedEvent').addEventListener('click', () => {
284
+ // dispatch event to say book page has flipped
285
+ document.querySelector('ia-book-actions').dispatchEvent(
286
+ new CustomEvent('BookReader:pageChanged', {
287
+ detail: { hasPageChanged: true },
288
+ bubbles: true,
289
+ composed: true,
290
+ })
291
+ );
292
+ })
295
293
  </script>
296
294
 
297
295
  <div>
@@ -302,6 +300,9 @@
302
300
  <td class="titleBar">
303
301
  <label><input type="checkbox" name="title" value="title" />Title Bar</label>
304
302
  </td>
303
+ <td>
304
+ <button class="pageChangedEvent">Page Change Event</button>
305
+ </td>
305
306
  </tr>
306
307
  </table>
307
308
  </fieldset>
@@ -311,7 +312,6 @@
311
312
  <table class="initial">
312
313
  <tr colspan='5'>
313
314
  <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
315
  </tr>
316
316
  <tr>
317
317
  <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-alpha2",
3
+ "version": "0.0.29-alpha21",
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,7 +22,8 @@
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
- "lit": "^2.2.1"
25
+ "@internetarchive/toast-manager": "0.0.1-alpha8",
26
+ "lit": "^2.5.0"
26
27
  },
27
28
  "devDependencies": {
28
29
  "@open-wc/eslint-config": "^4.2.0",
@@ -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: true,
103
+ isAdmin: false,
104
104
  isArchiveOrgLending: true,
105
105
  isAvailable: false,
106
106
  isAvailableForBrowsing: false,
@@ -12,6 +12,7 @@ export default css`
12
12
  }
13
13
  .actiongroup {
14
14
  display: flex;
15
+ margin-right: 10px;
15
16
  }
16
17
  .action-buttons {
17
18
  display: inline-flex;
@@ -33,12 +34,12 @@ export default css`
33
34
  }
34
35
  .primary {
35
36
  background-color: ${whiteColor};
37
+ margin-right: 4px;
36
38
  }
37
39
  .primary,
38
40
  .secondary {
39
41
  position: relative;
40
42
  border-radius: 5px;
41
- margin: 0 3px;
42
43
  }
43
44
  .primary .initial {
44
45
  border-radius: 4px 0 0 4px;
@@ -9,6 +9,10 @@ import CollapsibleActionGroupStyle from '../assets/styles/collapsible-action-gro
9
9
 
10
10
  import { tabletContainerWidth } from '../core/config/constants.js';
11
11
  import { purchaseIcon } from '../assets/data/purchase.js';
12
+ import {
13
+ analyticsCategories,
14
+ analyticsActions,
15
+ } from '../core/config/analytics-event-and-category.js';
12
16
  import {
13
17
  dropdownOpened,
14
18
  dropdownClosed,
@@ -28,8 +32,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
28
32
  dropdownArrow: { type: String },
29
33
  disabled: { type: Boolean },
30
34
  returnUrl: { type: String },
31
- browseAgainNow: { type: Boolean },
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.browseAgainNow = false;
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.browseAgainNow === true) {
65
- this.dispatchEvent(
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
  */
@@ -43,9 +43,6 @@ export class InfoIcon extends LitElement {
43
43
  vertical-align: middle;
44
44
  --iconFillColor: white;
45
45
  }
46
- .more-info-icon {
47
- margin-left: 10px;
48
- }
49
46
  .more-info-icon img {
50
47
  width: 24px;
51
48
  height: 24px;
@@ -26,7 +26,7 @@ export class TextGroup extends LitElement {
26
26
  display: inline-block;
27
27
  }
28
28
  .variable-texts {
29
- margin-left: 10px;
29
+ margin-right: 10px;
30
30
  vertical-align: middle;
31
31
  font-size: 1.7rem;
32
32
  }
@@ -5,44 +5,42 @@ 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 = 60;
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('resetTimerCountdown')) {
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
- // execute 50th minute check
40
- if (this.time === this.autoCheckAt) {
35
+ // execute from last 10th minute to 0th minute
36
+ // - 10th - to check if user has viewed
37
+ // - till 0th - to show warning msg with remaining time to auto returned
38
+ if (Math.round(this.time) <= this.autoCheckAt) {
41
39
  this.dispatchEvent(
42
- new CustomEvent('autoRenewAttempt', {
40
+ new CustomEvent('IABookActions:loanRenew', {
43
41
  detail: {
44
- remainingT: this.time,
45
- bookPageChange: false,
42
+ hasPageChanged: false,
43
+ timeLeft: Math.round(this.time),
46
44
  },
47
45
  bubbles: true,
48
46
  composed: true,
@@ -50,76 +48,65 @@ export default class TimerCountdown extends LitElement {
50
48
  );
51
49
  }
52
50
 
53
- if (this.time === 0) clearInterval(this.timerInterval);
54
-
51
+ // clear interval if timer is < this.autoCheckAt
52
+ if (this.time < this.autoCheckAt) {
53
+ clearInterval(this.timerInterval);
54
+ }
55
55
  }, 1000);
56
56
  }
57
57
 
58
-
59
58
  render() {
60
- return html`<div id="countdown">
61
- <div id="countdown-number">${this.time}</div>
62
- <svg>
63
- <circle r="18" cx="20" cy="20"></circle>
64
- </svg>
65
- </div>`
59
+ return html`
60
+ <svg
61
+ width="30"
62
+ height="30"
63
+ viewBox="0 0 100 100"
64
+ xmlns="http://www.w3.org/2000/svg"
65
+ >
66
+ <circle class="circle" cx="50" cy="50" r="50" />
67
+ </svg>
68
+ `;
66
69
  }
67
70
 
68
71
  static get styles() {
72
+ const white = css`var(--white, #fff)`;
73
+ const secondsLeft = css`var(--secondsLeft, 60s)`;
74
+
69
75
  return css`
70
76
  :host {
71
77
  right: 5px;
72
78
  font-size: 14px;
73
79
  position: absolute;
74
80
  }
75
- #countdown1 {
76
- position: relative;
77
- margin: auto;
78
- margin-top: 100px;
79
- height: 40px;
80
- width: 40px;
81
- text-align: center;
82
- }
83
-
84
- #countdown-number {
85
- color: white;
86
- display: inline-block;
87
- line-height: 40px;
88
- margin-right: 12px;
81
+
82
+ @keyframes circletimer {
83
+ 0% {
84
+ stroke-dashoffset: 320;
85
+ stroke-dasharray: 320;
86
+ }
87
+ 100% {
88
+ stroke-dashoffset: 0;
89
+ stroke-dasharray: 320;
90
+ }
89
91
  }
90
-
92
+
91
93
  svg {
94
+ background-color: transparent;
92
95
  position: absolute;
93
- top: 0;
96
+ top: 50%;
94
97
  right: 0;
95
- width: 40px;
96
- height: 40px;
97
- transform: rotateY(-180deg) rotateZ(-90deg);
98
- }
99
-
100
- svg circle {
101
- stroke-dasharray: 113px;
102
- stroke-dashoffset: 0px;
103
- stroke-linecap: round;
104
- stroke-width: 3px;
105
- stroke: white;
106
- fill: none;
107
- animation: countdown 60s linear infinite forwards;
98
+ border-radius: 50px;
99
+ border: 2px solid ${white};
100
+ transform: translate(-50%, -50%) rotateZ(-90deg);
108
101
  }
109
-
110
- @keyframes countdown {
111
- from {
112
- stroke-dashoffset: 0px;
113
- }
114
- to {
115
- stroke-dashoffset: 113px;
116
- }
117
- }
118
- .hidden {
119
- display: none;
120
- }
121
- .visible {
122
- display: inline-block;
102
+
103
+ svg .circle {
104
+ stroke: ${white};
105
+ stroke-width: 100px;
106
+ fill: transparent;
107
+ stroke-dashoffset: 320;
108
+ stroke-dasharray: 0;
109
+ animation: ${secondsLeft} circletimer linear;
123
110
  }
124
111
  `;
125
112
  }
@@ -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
- async bindEvents() {
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('autoBrowseBook', ({ detail }) => {
55
- console.log('auto renew handlerExecuted!!');
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,21 +117,27 @@ export default class ActionsHandler extends LitElement {
126
117
  });
127
118
  }
128
119
 
129
- handleAutoBrowseIt() {
130
- const action = 'auto_browse';
131
- this.setBrowseTimeSession()
120
+ handleLoanRenew() {
121
+ const action = 'renew_loan';
132
122
 
133
123
  ActionsHandlerService({
134
124
  action,
135
125
  identifier: this.identifier,
136
- success: () => {},
126
+ success: data => {
127
+ // success analytics by isa?
128
+ this.setBrowseTimeSession();
129
+ this.dispatchEvent(
130
+ new CustomEvent('loanAutoRenewed', {
131
+ detail: { action, data },
132
+ })
133
+ );
134
+ },
137
135
  error: data => {
138
136
  this.dispatchActionError(action, data);
139
137
  },
140
138
  });
141
139
  }
142
140
 
143
-
144
141
  handleReturnIt() {
145
142
  const action = 'return_loan';
146
143
  this.dispatchToggleActionGroup();
@@ -291,6 +288,28 @@ export default class ActionsHandler extends LitElement {
291
288
  }
292
289
  }
293
290
 
291
+ /**
292
+ * set browse time in indexedDB
293
+ */
294
+ async setBrowseTimeSession() {
295
+ try {
296
+ const { totalTime } = this.loanRenewConfig;
297
+ const expireDate = new Date(new Date().getTime() + totalTime * 1000);
298
+
299
+ // set a value
300
+ await this.localCache.set({
301
+ key: `${this.identifier}-loanTime`,
302
+ value: expireDate,
303
+ ttl: Number(totalTime),
304
+ });
305
+
306
+ // delete pageChangedTime when book is auto renew at nth minute
307
+ await this.localCache.delete(`${this.identifier}-pageChangedTime`);
308
+ } catch (error) {
309
+ console.log(error);
310
+ }
311
+ }
312
+
294
313
  deleteLoanCookies() {
295
314
  const date = new Date();
296
315
  date.setTime(date.getTime() - 24 * 60 * 60 * 1000); // one day ago
@@ -310,17 +329,4 @@ export default class ActionsHandler extends LitElement {
310
329
  '.archive.org'
311
330
  );
312
331
  }
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
332
  }