@internetarchive/ia-book-actions 0.0.7-3 → 0.0.7-4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/ia-book-actions",
3
- "version": "0.0.7-03",
3
+ "version": "0.0.7-4",
4
4
  "description": "Bookreader actions for borrowable book",
5
5
  "author": "Internet Archive",
6
6
  "license": "AGPL-3.0-only",
@@ -24,6 +24,7 @@
24
24
  "@internetarchive/icon-info": "^1.2.6",
25
25
  "@internetarchive/modal-manager": "^0.1.0",
26
26
  "@internetarchive/shared-resize-observer": "^0.0.1",
27
+ "idb-keyval": "^6.0.3",
27
28
  "lit-element": "^2.4.0",
28
29
  "lit-html": "^1.3.0"
29
30
  },
@@ -2,6 +2,7 @@ import { html } from 'lit-element';
2
2
  import { nothing } from 'lit-html';
3
3
  import { classMap } from 'lit-html/directives/class-map';
4
4
 
5
+ import { get as indexedDBGet } from 'idb-keyval';
5
6
  import ActionsHandler from '../core/services/actions-handler/actions-handler.js';
6
7
 
7
8
  import buttonBaseStyle from '../assets/styles/ia-button.js';
@@ -64,28 +65,35 @@ export class CollapsibleActionGroup extends ActionsHandler {
64
65
  }
65
66
 
66
67
  /**
67
- * Handles events when user is borrowing book and wants to have access to read
68
+ * Dispatches event when patron is borrowing book.
69
+ * Notes borrow type, and consecutive borrow counts
68
70
  *
69
71
  * @fires CollapsibleActionGroup#enableBookAccess
70
72
  */
71
- emitEnableBookAccess() {
73
+ async emitEnableBookAccess() {
72
74
  // send consecutiveLoanCounts for browsed books only.
73
- if (this.borrowType === 'browsing') {
74
- this.consecutiveLoanCounts =
75
- localStorage.getItem('consecutive-loan-count') ?? 1;
75
+ if (this.borrowType === 'browsed') {
76
+ try {
77
+ const existingCount = await indexedDBGet('consecutive-loan-count');
78
+ if (existingCount !== undefined) {
79
+ this.consecutiveLoanCounts = existingCount.value ?? 1;
80
+ }
81
+ } catch (error) {
82
+ console.log(error);
83
+ }
76
84
  }
77
85
 
78
86
  // event category and action for browsing book access
79
87
  const eventCategory = `${this.borrowType}BookAccess`;
80
88
  const eventAction = `${
81
- this.borrowType === 'browsing' ? 'BrowseCounts-' : 'Counts-'
89
+ this.borrowType === 'browsed' ? 'BrowseCounts-' : 'Counts-'
82
90
  }${this.consecutiveLoanCounts}`;
83
91
 
84
92
  this.dispatchEvent(
85
93
  new CustomEvent('enableBookAccess', {
86
94
  detail: {
87
95
  event: {
88
- category: eventCategory, // brosingBookAccess | borrowingBookAccess
96
+ category: eventCategory, // browsedBookAccess | borrowedBookAccess
89
97
  action: eventAction, // (BrowseCounts-N|Counts-N)
90
98
  },
91
99
  borrowType: this.borrowType,
@@ -226,7 +234,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
226
234
  }
227
235
 
228
236
  /**
229
- * Handles click events when user click on action buttons
237
+ * Dispatches click events when patron clicks on action buttons
230
238
  * @param { string } eventName - actions like 'browseBook', 'borrowBook' etc...
231
239
  * @param { object } gaEvent - contains analytics event action and category
232
240
  * @param { string } gaEvent.category
@@ -16,6 +16,11 @@ export default function ActionsHandlerService(options) {
16
16
  let baseHost = '/services/loans/loan';
17
17
  const location = window?.location;
18
18
 
19
+ // return intentional error on dev environment
20
+ const shouldReturnError =
21
+ location?.href?.indexOf('?error=true') !== -1 &&
22
+ location?.hostname !== 'archive.org';
23
+
19
24
  if (location?.pathname === '/demo/') baseHost = `/demo/`;
20
25
 
21
26
  let formData = new FormData();
@@ -27,12 +32,11 @@ export default function ActionsHandlerService(options) {
27
32
  body: formData,
28
33
  })
29
34
  .then(response => {
30
- let shouldReturnError = location?.href?.indexOf('?error=true') !== -1;
31
35
  const tokenError = 'loan token not found. please try again later.';
32
36
  const borrowError =
33
37
  'This book is not available to borrow at this time. Please try again later.';
34
38
 
35
- // return error reponse if query param has ?error=true param...
39
+ // return error reponse when not production and has ?error=true param...
36
40
  const erroneousActions = ['browse_book', 'borrow_book', 'create_token'];
37
41
  if (shouldReturnError && erroneousActions.includes(option?.action)) {
38
42
  return {
@@ -1,4 +1,6 @@
1
1
  import { LitElement } from 'lit-element';
2
+ import { get as indexedDBGet, set as indexedDBSet } from 'idb-keyval';
3
+
2
4
  import { URLHelper } from '../../config/url-helper.js';
3
5
  import ActionsHandlerService from './actions-handler-service.js';
4
6
 
@@ -211,6 +213,15 @@ export default class ActionsHandler extends LitElement {
211
213
  });
212
214
  }
213
215
 
216
+ /**
217
+ * Dispatches event when an error occured on action
218
+ * Notes:- toggle <collapsible-action-group> visibility (enable/disable).
219
+ *
220
+ * @param { String } action - name of action like browse_book, borrow_book
221
+ * @param { Object } data - erroneous response from api call
222
+ *
223
+ * @fires ActionsHandler#lendingActionError
224
+ */
214
225
  dispatchActionError(action, data = {}) {
215
226
  this.dispatchEvent(
216
227
  new CustomEvent('lendingActionError', {
@@ -219,6 +230,12 @@ export default class ActionsHandler extends LitElement {
219
230
  );
220
231
  }
221
232
 
233
+ /**
234
+ * Dispatches event when patron is clicked on action buttons.
235
+ * Notes:- toggle <collapsible-action-group> disable/enable.
236
+ *
237
+ * @fires ActionsHandler#toggleActionGroup
238
+ */
222
239
  dispatchToggleActionGroup() {
223
240
  this.dispatchEvent(new CustomEvent('toggleActionGroup'));
224
241
  }
@@ -256,19 +273,28 @@ export default class ActionsHandler extends LitElement {
256
273
  }
257
274
 
258
275
  // save consecutive loan count for borrow
259
- setConsecutiveLoanCounts(action = '') {
260
- const { localStorage } = window;
261
- if (localStorage) {
276
+ async setConsecutiveLoanCounts(action = '') {
277
+ try {
262
278
  let newCount = 1;
263
279
  const storageKey = `consecutive-loan-count`;
264
- const existingCount = Number(localStorage.getItem(storageKey));
280
+ const existingCount = await indexedDBGet(storageKey);
281
+
282
+ // expire indexDB key-value after 2 hours
283
+ const expireTime = new Date(
284
+ Date.now() + (1 / 12) * 24 * 60 * 60 * 1000
285
+ ).toString();
265
286
 
266
- // want to increase browse-count by 1 if,
267
- // you consecutive reading a book.
268
- if (action === 'browseAgain') {
269
- newCount = existingCount ? existingCount + 1 : 1;
287
+ // increase browse-count by 1 when you consecutive reading a book.
288
+ if (action === 'browseAgain' && existingCount !== undefined) {
289
+ newCount = existingCount.value ? existingCount.value + 1 : 1;
270
290
  }
271
- localStorage.setItem(storageKey, newCount);
291
+
292
+ await indexedDBSet(storageKey, {
293
+ value: newCount,
294
+ expire: expireTime,
295
+ });
296
+ } catch (error) {
297
+ console.log(error);
272
298
  }
273
299
  }
274
300
 
@@ -96,7 +96,7 @@ export default class GetLendingActions {
96
96
  this.actionsConfig.adminAccessConfig(),
97
97
  this.actionsConfig.purchaseConfig(),
98
98
  ],
99
- borrowType: isBrowsing ? 'browsing' : 'borrowing',
99
+ borrowType: isBrowsing ? 'browsed' : 'borrowed',
100
100
  };
101
101
  }
102
102
 
@@ -24,6 +24,7 @@ export default class IABookActions extends LitElement {
24
24
  barType: { type: String },
25
25
  sharedObserver: { attribute: false },
26
26
  disableActionGroup: { type: Boolean },
27
+ modal: { Object },
27
28
  };
28
29
  }
29
30
 
@@ -37,12 +38,15 @@ export default class IABookActions extends LitElement {
37
38
  this.bwbPurchaseUrl = '';
38
39
  this.barType = 'action'; // 'title'|'action'
39
40
  this.sharedObserver = undefined;
41
+ this.disableActionGroup = false;
42
+ this.modal = undefined;
43
+
44
+ // private props
40
45
  this.primaryActions = [];
41
46
  this.primaryTitle = '';
42
47
  this.primaryColor = 'primary';
43
48
  this.secondaryActions = [];
44
49
  this.lendingOptions = {};
45
- this.disableActionGroup = false;
46
50
  }
47
51
 
48
52
  disconnectedCallback() {
@@ -144,8 +148,8 @@ export default class IABookActions extends LitElement {
144
148
  });
145
149
 
146
150
  this.borrowType = actions.borrowType;
147
- if (this.borrowType === 'browsing') {
148
- // start timer for browsing.
151
+ if (this.borrowType === 'browsed') {
152
+ // start timer for browsed.
149
153
  // when browse is completed, we shows browse-again button
150
154
  this.startBrowseTimer();
151
155
  }
@@ -235,11 +239,15 @@ export default class IABookActions extends LitElement {
235
239
  async showErrorModal(errorMsg, action) {
236
240
  this.disableActionGroup = false;
237
241
 
238
- this.modal = document.querySelector('#action-bar-modal');
242
+ // check if this.modal passed as prop
239
243
  if (!this.modal) {
240
- this.modal = document.createElement('modal-manager');
241
- this.modal.id = 'action-bar-modal';
244
+ this.modal = document.querySelector('modal-manager');
245
+
246
+ // check the DOM if <modal-manager> already there
247
+ if (!this.modal) this.modal = document.createElement('modal-manager');
242
248
  }
249
+
250
+ this.modal.id = 'action-bar-modal';
243
251
  await document.body.appendChild(this.modal);
244
252
 
245
253
  const modalConfig = new ModalConfig({
@@ -253,7 +261,8 @@ export default class IABookActions extends LitElement {
253
261
  modalConfig.showCloseButton = false;
254
262
  modalConfig.message = html` Uh oh, something went wrong trying to access
255
263
  this book.<br />
256
- Please <a href="/">refresh</a> to try again or send us an email to
264
+ Please <a href="${() => window.location.reload(true)}">refresh</a> to
265
+ try again or send us an email to
257
266
  <a
258
267
  href="mailto:info@archive.org?subject=Help: cannot access my borrowed book: ${this
259
268
  .identifier}"
@@ -1,6 +1,5 @@
1
1
  import { html, fixture, expect } from '@open-wc/testing';
2
2
  import '../../src/components/collapsible-action-group.js';
3
- import Sinon from 'sinon';
4
3
 
5
4
  const container = ({
6
5
  primaryActions = [
@@ -85,27 +84,3 @@ describe('<collapsible-action-group>', () => {
85
84
  expect(eAnalytics.action).to.equal('Browse');
86
85
  });
87
86
  });
88
-
89
- describe('fetch loan token and localStorage for browsed/borrowsed book', () => {
90
- beforeEach(() => {
91
- const localStorageMock = {
92
- getItem: Sinon.spy(),
93
- setItem: Sinon.spy(),
94
- };
95
- Object.defineProperty(window, 'localStorage', {
96
- value: localStorageMock,
97
- });
98
- });
99
-
100
- it('test localStorage function when borrowType is browsing', async () => {
101
- await fixture(container({ borrowType: 'browsing' }));
102
- expect(localStorage.getItem).to.be.calledOnce;
103
- expect(localStorage.getItem).to.be.calledWith('consecutive-loan-count');
104
- });
105
-
106
- it('test localStorage function when borrowType is borrowing', async () => {
107
- await fixture(container({ borrowType: 'borrowing' }));
108
- expect(localStorage.getItem).to.not.be.calledOnce;
109
- expect(localStorage.getItem).to.not.be.calledWith('consecutive-loan-count');
110
- });
111
- });