@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 +2 -1
- package/src/components/collapsible-action-group.js +16 -8
- package/src/core/services/actions-handler/actions-handler-service.js +6 -2
- package/src/core/services/actions-handler/actions-handler.js +35 -9
- package/src/core/services/get-lending-actions.js +1 -1
- package/src/ia-book-actions.js +16 -7
- package/test/components/collapsible-action-group.test.js +0 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@internetarchive/ia-book-actions",
|
|
3
|
-
"version": "0.0.7-
|
|
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
|
-
*
|
|
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 === '
|
|
74
|
-
|
|
75
|
-
|
|
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 === '
|
|
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, //
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
261
|
-
if (localStorage) {
|
|
276
|
+
async setConsecutiveLoanCounts(action = '') {
|
|
277
|
+
try {
|
|
262
278
|
let newCount = 1;
|
|
263
279
|
const storageKey = `consecutive-loan-count`;
|
|
264
|
-
const existingCount =
|
|
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
|
-
//
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
|
|
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
|
|
package/src/ia-book-actions.js
CHANGED
|
@@ -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 === '
|
|
148
|
-
// start timer for
|
|
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
|
|
242
|
+
// check if this.modal passed as prop
|
|
239
243
|
if (!this.modal) {
|
|
240
|
-
this.modal = document.
|
|
241
|
-
|
|
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="
|
|
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
|
-
});
|