@internetarchive/ia-book-actions 0.0.6 → 0.0.7-3
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/README.md +93 -47
- package/assets/ia-book-action-screen.png +0 -0
- package/assets/ia-book-title-screen.png +0 -0
- package/demo/index.html +41 -2
- package/package.json +3 -1
- package/src/assets/styles/collapsible-action-group.js +10 -2
- package/src/components/collapsible-action-group.js +69 -11
- package/src/core/services/actions-handler/actions-handler-service.js +35 -29
- package/src/core/services/actions-handler/actions-handler.js +112 -12
- package/src/core/services/get-lending-actions.js +4 -1
- package/src/ia-book-actions.js +94 -7
- package/test/components/collapsible-action-group.test.js +43 -0
- package/test/ia-book-actions.test.js +58 -0
package/README.md
CHANGED
|
@@ -1,69 +1,115 @@
|
|
|
1
|
-
|
|
1
|
+
# Component for lendable and embed items
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The book action button component build on LitElement with support for custom content and light DOM elements.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Usage
|
|
8
|
-
|
|
9
|
-
1. Click the "Use this Template" button in GitHub to create a new repository based on this one.
|
|
10
|
-
2. Clone your new repo and update the things below.
|
|
11
|
-
|
|
12
|
-
### Things to update in your copy
|
|
13
|
-
1. Remove this section
|
|
14
|
-
2. Search for the strings `your-webcomponent` and `YourWebComponent` and those are most of the spots that need to be updated.
|
|
15
|
-
3. `README.md` (this file). Update the readme in general, but also the badge URLs
|
|
16
|
-
4. `package.json` Update the name and description
|
|
17
|
-
5. Rename the `your-webcomponent.ts` and its associated `.test` file
|
|
18
|
-
6. Update `.travis.yml` with the proper secure key. See the [Travis docs](https://blog.travis-ci.com/2014-03-13-slack-notifications/) for more information.
|
|
19
|
-
|
|
20
|
-
## Local Demo with `web-dev-server`
|
|
5
|
+
## Installation
|
|
21
6
|
```bash
|
|
22
|
-
yarn
|
|
7
|
+
yarn install --save @internetarchive/ia-book-actions
|
|
23
8
|
```
|
|
24
|
-
To run a local development server that serves the basic demo located in `demo/index.html`
|
|
25
9
|
|
|
26
|
-
##
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
10
|
+
## Usage of Book Actions
|
|
11
|
+
```html
|
|
12
|
+
<!-- index.html -->
|
|
13
|
+
<style>
|
|
14
|
+
html {
|
|
15
|
+
font-size: 10px;
|
|
16
|
+
/* This is to match petabox's base font size */
|
|
17
|
+
}
|
|
18
|
+
body {
|
|
19
|
+
margin: 0;
|
|
20
|
+
text-align: center;
|
|
21
|
+
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
22
|
+
}
|
|
23
|
+
#demo {
|
|
24
|
+
height: 50px;
|
|
25
|
+
}
|
|
26
|
+
ia-book-actions {
|
|
27
|
+
--white: #fff;
|
|
28
|
+
--black: #000;
|
|
29
|
+
--primaryBGColor: var(--black);
|
|
30
|
+
--secondaryBGColor: #222;
|
|
31
|
+
--tertiaryBGColor: #333;
|
|
32
|
+
--primaryTextColor: var(--white);
|
|
33
|
+
--primaryCTAFill: #194880;
|
|
34
|
+
--primaryCTABorder: #c5d1df;
|
|
35
|
+
--secondaryCTAFill: #333;
|
|
36
|
+
--secondaryCTABorder: #999;
|
|
37
|
+
--secondaryCTAFillRGB: 51, 51, 51;
|
|
38
|
+
--primaryErrorCTAFill: #e51c26;
|
|
39
|
+
--primaryErrorCTABorder: #f8c6c8;
|
|
40
|
+
--primaryCTAFillRGB: 25, 72, 128;
|
|
41
|
+
--primaryErrorCTAFillRGB: 229, 28, 38;
|
|
42
|
+
--primaryDisableCTAFill: #767676;
|
|
43
|
+
}
|
|
44
|
+
</style>
|
|
45
|
+
|
|
46
|
+
<ia-book-actions></ia-book-actions>
|
|
47
|
+
|
|
48
|
+
<script type="module">
|
|
49
|
+
import '@internetarchive/ia-book-actions.js';
|
|
50
|
+
import { ModalConfig } from '@internetarchive/modal-manager';
|
|
51
|
+
import {
|
|
52
|
+
defaultLendingStatus,
|
|
53
|
+
canBrowseAndBorrow,
|
|
54
|
+
} from '../src/assets/data/lending-get-status-service.js';
|
|
55
|
+
|
|
56
|
+
let iaBookActions = document.querySelector('ia-book-actions');
|
|
57
|
+
iaBookActions.userid = '@neeraj-archive';
|
|
58
|
+
iaBookActions.identifier = 'naturalhistoryof00unse_4111';
|
|
59
|
+
iaBookActions.bookTitle = 'This is test title for any book';
|
|
60
|
+
iaBookActions.lendingStatus = {}; // lendinStatus in json
|
|
61
|
+
iaBookActions.bwbPurchaseUrl = 'https://bwb.com/produce/123';
|
|
62
|
+
iaBookActions.barType = ''; // title|action
|
|
63
|
+
</script>
|
|
30
64
|
```
|
|
31
65
|
|
|
32
|
-
|
|
66
|
+

|
|
33
67
|
|
|
34
|
-
|
|
35
|
-
|
|
68
|
+
## Usage of Book Title
|
|
69
|
+
```html
|
|
70
|
+
<!-- along with above properties, set barType to 'title' -->
|
|
71
|
+
<script type="module">
|
|
72
|
+
iaBookActions.barType = 'title'; // title|action
|
|
73
|
+
</script>
|
|
36
74
|
```
|
|
75
|
+

|
|
37
76
|
|
|
38
|
-
|
|
39
|
-
To scan the project for linting errors, run
|
|
40
|
-
```bash
|
|
41
|
-
yarn run lint
|
|
42
|
-
```
|
|
77
|
+
### Config Options
|
|
43
78
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
79
|
+
All of the config options:
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
let iaBookActions = document.querySelector('ia-book-actions');
|
|
83
|
+
const modalConfig = new ModalConfig(); // to show info/error modal
|
|
84
|
+
|
|
85
|
+
// set defaultLendingStatus for unavailable (without borrowables) book
|
|
86
|
+
iaBookActions.userid = '@jack';
|
|
87
|
+
iaBookActions.identifier = 'jack-sparrow';
|
|
88
|
+
iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
|
|
89
|
+
iaBookActions.lendingStatus = {active_borrows: 0, active_browses: 0}, // complete lendingStatus object
|
|
90
|
+
iaBookActions.bwbPurchaseUrl = ''; // BWB purchase URl if any
|
|
91
|
+
iaBookActions.barType = '';
|
|
92
|
+
iaBookActions.modalConfig = modalConfig;
|
|
47
93
|
```
|
|
94
|
+
|
|
95
|
+
# Development
|
|
96
|
+
|
|
97
|
+
## Prerequisite
|
|
48
98
|
```bash
|
|
49
|
-
yarn
|
|
99
|
+
yarn install
|
|
50
100
|
```
|
|
51
101
|
|
|
52
|
-
|
|
102
|
+
## Start Development Server
|
|
53
103
|
```bash
|
|
54
|
-
yarn
|
|
104
|
+
yarn start
|
|
55
105
|
```
|
|
56
106
|
|
|
57
|
-
|
|
107
|
+
## Testing
|
|
58
108
|
```bash
|
|
59
|
-
yarn
|
|
109
|
+
yarn test
|
|
60
110
|
```
|
|
111
|
+
|
|
112
|
+
## Linting
|
|
61
113
|
```bash
|
|
62
|
-
yarn
|
|
114
|
+
yarn lint
|
|
63
115
|
```
|
|
64
|
-
|
|
65
|
-
## Tooling configs
|
|
66
|
-
|
|
67
|
-
For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project.
|
|
68
|
-
|
|
69
|
-
If you customize the configuration a lot, you can consider moving them to individual files.
|
|
Binary file
|
|
Binary file
|
package/demo/index.html
CHANGED
|
@@ -71,6 +71,14 @@
|
|
|
71
71
|
float: left;
|
|
72
72
|
margin: 2px;
|
|
73
73
|
}
|
|
74
|
+
|
|
75
|
+
body.modal-manager-open {
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
modal-manager[mode='closed'] {
|
|
80
|
+
display: none;
|
|
81
|
+
}
|
|
74
82
|
</style>
|
|
75
83
|
</head>
|
|
76
84
|
|
|
@@ -85,6 +93,7 @@
|
|
|
85
93
|
defaultLendingStatus,
|
|
86
94
|
canBrowseAndBorrow,
|
|
87
95
|
} from '../src/assets/data/lending-get-status-service.js';
|
|
96
|
+
import { ModalConfig } from '@internetarchive/modal-manager';
|
|
88
97
|
|
|
89
98
|
const userid = '@neeraj-archive';
|
|
90
99
|
const identifier = 'naturalhistoryof00unse_4111';
|
|
@@ -92,13 +101,17 @@
|
|
|
92
101
|
|
|
93
102
|
let iaBookActions = document.querySelector('ia-book-actions');
|
|
94
103
|
|
|
104
|
+
const modalConfig = new ModalConfig();
|
|
105
|
+
modalConfig.headerColor = '#d9534f';
|
|
106
|
+
|
|
95
107
|
// set defaultLendingStatus for unavailable (without borrowables) book
|
|
96
|
-
iaBookActions.userid =
|
|
108
|
+
iaBookActions.userid = userid;
|
|
97
109
|
iaBookActions.identifier = identifier;
|
|
98
110
|
iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
|
|
99
|
-
iaBookActions.lendingStatus =
|
|
111
|
+
iaBookActions.lendingStatus = canBrowseAndBorrow;
|
|
100
112
|
iaBookActions.bwbPurchaseUrl = '';
|
|
101
113
|
iaBookActions.barType = '';
|
|
114
|
+
iaBookActions.modalConfig = modalConfig;
|
|
102
115
|
|
|
103
116
|
let lendingStatus1 = iaBookActions.lendingStatus;
|
|
104
117
|
|
|
@@ -112,6 +125,29 @@
|
|
|
112
125
|
});
|
|
113
126
|
});
|
|
114
127
|
|
|
128
|
+
document.querySelectorAll('.errorEnable input[type=checkbox]').forEach((item) => {
|
|
129
|
+
if (window.location.href.indexOf('?error=true') !== -1) {
|
|
130
|
+
item.checked = true;
|
|
131
|
+
}
|
|
132
|
+
item.addEventListener('click', (e) => {
|
|
133
|
+
var searchParams = new URLSearchParams(window.location.search);
|
|
134
|
+
var separate = '';
|
|
135
|
+
if (e.target.checked) {
|
|
136
|
+
separate = '?';
|
|
137
|
+
searchParams.set('error', true);
|
|
138
|
+
} else {
|
|
139
|
+
separate = '';
|
|
140
|
+
searchParams.delete('error');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (history.pushState) {
|
|
144
|
+
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + separate + searchParams;
|
|
145
|
+
window.history.pushState({path:newurl},'',newurl);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
|
|
115
151
|
document.querySelectorAll('.userState input[type=checkbox]').forEach((item) => {
|
|
116
152
|
item.addEventListener('click', (e) => {
|
|
117
153
|
if (e.target.checked) {
|
|
@@ -219,6 +255,9 @@
|
|
|
219
255
|
<fieldset>
|
|
220
256
|
<legend>Dev testing for book action bar</legend>
|
|
221
257
|
<table class="initial">
|
|
258
|
+
<tr colspan='5'>
|
|
259
|
+
<td class="errorEnable"><label><input type="checkbox" name="errorEnable" value="errorEnable" />Do you want to see error response?</label></td>
|
|
260
|
+
</tr>
|
|
222
261
|
<tr>
|
|
223
262
|
<td class="userState">
|
|
224
263
|
<label><input type="checkbox" name="user" value="isAdmin" />isAdmin</label>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@internetarchive/ia-book-actions",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7-03",
|
|
4
4
|
"description": "Bookreader actions for borrowable book",
|
|
5
5
|
"author": "Internet Archive",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@internetarchive/ia-icons": "^1.2.2",
|
|
22
22
|
"@internetarchive/icon-bookmark": "^1.1.3",
|
|
23
|
+
"@internetarchive/icon-close": "^1.1.3",
|
|
23
24
|
"@internetarchive/icon-info": "^1.2.6",
|
|
25
|
+
"@internetarchive/modal-manager": "^0.1.0",
|
|
24
26
|
"@internetarchive/shared-resize-observer": "^0.0.1",
|
|
25
27
|
"lit-element": "^2.4.0",
|
|
26
28
|
"lit-html": "^1.3.0"
|
|
@@ -6,6 +6,9 @@ export default css`
|
|
|
6
6
|
height: 3.5rem;
|
|
7
7
|
padding: 1rem 0;
|
|
8
8
|
}
|
|
9
|
+
.actiongroup {
|
|
10
|
+
display: flex;
|
|
11
|
+
}
|
|
9
12
|
.action-buttons {
|
|
10
13
|
display: inline-flex;
|
|
11
14
|
align-items: center;
|
|
@@ -80,7 +83,7 @@ export default css`
|
|
|
80
83
|
padding: 0 0.6rem;
|
|
81
84
|
margin-left: 0;
|
|
82
85
|
}
|
|
83
|
-
.
|
|
86
|
+
.actionloader {
|
|
84
87
|
vertical-align: middle;
|
|
85
88
|
visibility: hidden;
|
|
86
89
|
padding: 0.9rem 0.2rem;
|
|
@@ -129,9 +132,14 @@ export default css`
|
|
|
129
132
|
display: initial;
|
|
130
133
|
font-size: 1.4rem;
|
|
131
134
|
}
|
|
132
|
-
|
|
133
135
|
.unavailable {
|
|
134
136
|
opacity: 0.7;
|
|
135
137
|
pointer-events: none;
|
|
136
138
|
}
|
|
139
|
+
|
|
140
|
+
.disabled {
|
|
141
|
+
opacity: 0.8;
|
|
142
|
+
pointer-events: none;
|
|
143
|
+
visibility: visible;
|
|
144
|
+
}
|
|
137
145
|
`;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { html } from 'lit-element';
|
|
2
2
|
import { nothing } from 'lit-html';
|
|
3
|
+
import { classMap } from 'lit-html/directives/class-map';
|
|
3
4
|
|
|
4
5
|
import ActionsHandler from '../core/services/actions-handler/actions-handler.js';
|
|
5
6
|
|
|
@@ -25,6 +26,8 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
25
26
|
width: { type: Number },
|
|
26
27
|
hasAdminAccess: { type: Boolean },
|
|
27
28
|
dropdownArrow: { type: String },
|
|
29
|
+
disabled: { type: Boolean },
|
|
30
|
+
borrowType: { type: String },
|
|
28
31
|
};
|
|
29
32
|
}
|
|
30
33
|
|
|
@@ -42,6 +45,9 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
42
45
|
this.initialButton = false;
|
|
43
46
|
this.title = '';
|
|
44
47
|
this.loaderIcon = 'https://archive.org/upload/images/tree/loading.gif';
|
|
48
|
+
this.disabled = false;
|
|
49
|
+
this.borrowType = ''; // (browsed|borrowed)
|
|
50
|
+
this.consecutiveLoanCounts = 1; // consecutive loan count
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
updated(changed) {
|
|
@@ -50,6 +56,42 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
50
56
|
this.resetActions();
|
|
51
57
|
}
|
|
52
58
|
}
|
|
59
|
+
|
|
60
|
+
// this is execute to fetch loan token
|
|
61
|
+
if (changed.has('borrowType')) {
|
|
62
|
+
this.emitEnableBookAccess();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Handles events when user is borrowing book and wants to have access to read
|
|
68
|
+
*
|
|
69
|
+
* @fires CollapsibleActionGroup#enableBookAccess
|
|
70
|
+
*/
|
|
71
|
+
emitEnableBookAccess() {
|
|
72
|
+
// send consecutiveLoanCounts for browsed books only.
|
|
73
|
+
if (this.borrowType === 'browsing') {
|
|
74
|
+
this.consecutiveLoanCounts =
|
|
75
|
+
localStorage.getItem('consecutive-loan-count') ?? 1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// event category and action for browsing book access
|
|
79
|
+
const eventCategory = `${this.borrowType}BookAccess`;
|
|
80
|
+
const eventAction = `${
|
|
81
|
+
this.borrowType === 'browsing' ? 'BrowseCounts-' : 'Counts-'
|
|
82
|
+
}${this.consecutiveLoanCounts}`;
|
|
83
|
+
|
|
84
|
+
this.dispatchEvent(
|
|
85
|
+
new CustomEvent('enableBookAccess', {
|
|
86
|
+
detail: {
|
|
87
|
+
event: {
|
|
88
|
+
category: eventCategory, // brosingBookAccess | borrowingBookAccess
|
|
89
|
+
action: eventAction, // (BrowseCounts-N|Counts-N)
|
|
90
|
+
},
|
|
91
|
+
borrowType: this.borrowType,
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
);
|
|
53
95
|
}
|
|
54
96
|
|
|
55
97
|
/**
|
|
@@ -94,13 +136,20 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
94
136
|
|
|
95
137
|
render() {
|
|
96
138
|
return html`
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
139
|
+
<div
|
|
140
|
+
class="${classMap({
|
|
141
|
+
actiongroup: true,
|
|
142
|
+
disabled: this.disabled,
|
|
143
|
+
})}"
|
|
144
|
+
>
|
|
145
|
+
${this.getLoaderIcon}
|
|
146
|
+
<section class="action-buttons primary">
|
|
147
|
+
${this.renderPrimaryActions}
|
|
148
|
+
</section>
|
|
149
|
+
<section class="action-buttons secondary">
|
|
150
|
+
${this.renderSecondaryActions}
|
|
151
|
+
</section>
|
|
152
|
+
</div>
|
|
104
153
|
`;
|
|
105
154
|
}
|
|
106
155
|
|
|
@@ -177,11 +226,13 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
177
226
|
}
|
|
178
227
|
|
|
179
228
|
/**
|
|
180
|
-
*
|
|
181
|
-
* @param { string } eventName
|
|
182
|
-
* @param { object } gaEvent
|
|
229
|
+
* Handles click events when user click on action buttons
|
|
230
|
+
* @param { string } eventName - actions like 'browseBook', 'borrowBook' etc...
|
|
231
|
+
* @param { object } gaEvent - contains analytics event action and category
|
|
183
232
|
* @param { string } gaEvent.category
|
|
184
233
|
* @param { string } gaEvent.action
|
|
234
|
+
*
|
|
235
|
+
* @fires CollapsibleActionGroup#{eventName} - (will be browseBook, borrowBook etc...)
|
|
185
236
|
*/
|
|
186
237
|
clickHandler(eventName, gaEvent) {
|
|
187
238
|
this.dropdownState = 'close';
|
|
@@ -225,7 +276,14 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
225
276
|
* @returns { HTMLElement }
|
|
226
277
|
*/
|
|
227
278
|
get getLoaderIcon() {
|
|
228
|
-
return html`<img
|
|
279
|
+
return html`<img
|
|
280
|
+
class="${classMap({
|
|
281
|
+
actionloader: true,
|
|
282
|
+
disabled: this.disabled,
|
|
283
|
+
})}"
|
|
284
|
+
alt=""
|
|
285
|
+
src="${this.loaderIcon}"
|
|
286
|
+
/>`;
|
|
229
287
|
}
|
|
230
288
|
|
|
231
289
|
/**
|
|
@@ -8,24 +8,15 @@ export default function ActionsHandlerService(options) {
|
|
|
8
8
|
const option = {
|
|
9
9
|
action: null,
|
|
10
10
|
identifier: '',
|
|
11
|
-
data: {},
|
|
12
11
|
success() {},
|
|
13
|
-
error
|
|
14
|
-
loader: true,
|
|
15
|
-
type: 'POST',
|
|
12
|
+
error() {},
|
|
16
13
|
...options,
|
|
17
14
|
};
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
16
|
+
let baseHost = '/services/loans/loan';
|
|
17
|
+
const location = window?.location;
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
if (window.location.pathname === '/demo/') {
|
|
25
|
-
baseHost = `/demo/`;
|
|
26
|
-
} else {
|
|
27
|
-
baseHost = `/services/loans/loan`;
|
|
28
|
-
}
|
|
19
|
+
if (location?.pathname === '/demo/') baseHost = `/demo/`;
|
|
29
20
|
|
|
30
21
|
let formData = new FormData();
|
|
31
22
|
formData.append('action', option.action);
|
|
@@ -36,23 +27,38 @@ export default function ActionsHandlerService(options) {
|
|
|
36
27
|
body: formData,
|
|
37
28
|
})
|
|
38
29
|
.then(response => {
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
let shouldReturnError = location?.href?.indexOf('?error=true') !== -1;
|
|
31
|
+
const tokenError = 'loan token not found. please try again later.';
|
|
32
|
+
const borrowError =
|
|
33
|
+
'This book is not available to borrow at this time. Please try again later.';
|
|
34
|
+
|
|
35
|
+
// return error reponse if query param has ?error=true param...
|
|
36
|
+
const erroneousActions = ['browse_book', 'borrow_book', 'create_token'];
|
|
37
|
+
if (shouldReturnError && erroneousActions.includes(option?.action)) {
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
error: option?.action === 'create_token' ? tokenError : borrowError,
|
|
41
|
+
};
|
|
41
42
|
}
|
|
42
|
-
})
|
|
43
|
-
.catch(error => {
|
|
44
|
-
console.log(error);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
// return success response for /demo/ server...
|
|
45
|
+
if (baseHost == '/demo/1' || baseHost == '/demo/') {
|
|
46
|
+
return {
|
|
47
|
+
success: true,
|
|
48
|
+
message: 'operation executed successfully!',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
// The response is a Response instance.
|
|
53
|
+
// You parse the data into a useable format using `.json()`
|
|
54
|
+
return response.json();
|
|
55
|
+
})
|
|
56
|
+
.then(data => {
|
|
57
|
+
// `data` is the parsed version of the JSON returned from the above endpoint.
|
|
58
|
+
if (!data?.error) {
|
|
59
|
+
option?.success(data);
|
|
60
|
+
} else {
|
|
61
|
+
option?.error(data);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
58
64
|
}
|
|
@@ -7,33 +7,45 @@ import ActionsHandlerService from './actions-handler-service.js';
|
|
|
7
7
|
*
|
|
8
8
|
* ActionsHandlerService is a function being used to execute
|
|
9
9
|
* APIs based of the request made by user. It consist some parameters are as follows:-
|
|
10
|
-
* 1.
|
|
11
|
-
* 2. identifier: book name.
|
|
12
|
-
* 3. success: This is callback function which will be executed after the API request
|
|
13
|
-
* return reponse as a success.
|
|
10
|
+
* 1. identifier: book name.
|
|
14
11
|
*/
|
|
15
12
|
|
|
16
13
|
export default class ActionsHandler extends LitElement {
|
|
17
14
|
constructor(identifier) {
|
|
18
15
|
super();
|
|
19
16
|
this.identifier = identifier;
|
|
20
|
-
this.ajaxTimeout =
|
|
17
|
+
this.ajaxTimeout = 7000;
|
|
18
|
+
this.loanTokenPollingDelay =
|
|
19
|
+
window.location.pathname === '/demo/' ? 2000 : 120000; // 120000 ms = 2 min
|
|
20
|
+
this.loanTokenInterval = undefined;
|
|
21
21
|
this.bindEvents();
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
disconnectedCallback() {
|
|
25
|
+
this.loanTokenInterval = undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
24
28
|
sendEvent(eventCategory, eventAction) {
|
|
25
29
|
// eslint-disable-next-line no-console
|
|
26
30
|
console?.log('Book action: ', { eventCategory, eventAction });
|
|
27
|
-
window?.archive_analytics?.
|
|
31
|
+
window?.archive_analytics?.send_event_no_sampling(
|
|
28
32
|
eventCategory,
|
|
29
33
|
eventAction,
|
|
30
|
-
|
|
34
|
+
`identifier=${this.identifier}`
|
|
31
35
|
);
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
bindEvents() {
|
|
35
39
|
this.addEventListener('browseBook', ({ detail }) => {
|
|
36
40
|
this.handleBrowseIt();
|
|
41
|
+
this.setConsecutiveLoanCounts();
|
|
42
|
+
const { category, action } = detail.event;
|
|
43
|
+
this.sendEvent(category, action);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
this.addEventListener('browseBookAgain', ({ detail }) => {
|
|
47
|
+
this.handleBrowseIt();
|
|
48
|
+
this.setConsecutiveLoanCounts('browseAgain');
|
|
37
49
|
const { category, action } = detail.event;
|
|
38
50
|
this.sendEvent(category, action);
|
|
39
51
|
});
|
|
@@ -87,59 +99,130 @@ export default class ActionsHandler extends LitElement {
|
|
|
87
99
|
const { category, action } = detail.event;
|
|
88
100
|
this.sendEvent(category, action);
|
|
89
101
|
});
|
|
102
|
+
|
|
103
|
+
this.addEventListener('enableBookAccess', ({ detail }) => {
|
|
104
|
+
const borrowType = detail?.borrowType;
|
|
105
|
+
|
|
106
|
+
// fetch loan token for browsed/borrowed book and set an interval
|
|
107
|
+
if (borrowType) {
|
|
108
|
+
this.loanTokenInterval = setInterval(() => {
|
|
109
|
+
this.handleLoanTokenPoller();
|
|
110
|
+
}, this.loanTokenPollingDelay);
|
|
111
|
+
|
|
112
|
+
const { category, action } = detail?.event;
|
|
113
|
+
this.sendEvent(category, action);
|
|
114
|
+
} else {
|
|
115
|
+
// if book is not browsed, just clear token polling interval
|
|
116
|
+
clearInterval(this.loanTokenInterval);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
90
119
|
}
|
|
91
120
|
|
|
92
121
|
handleBrowseIt() {
|
|
122
|
+
const action = 'browse_book';
|
|
123
|
+
this.dispatchToggleActionGroup();
|
|
124
|
+
|
|
93
125
|
ActionsHandlerService({
|
|
94
|
-
action
|
|
126
|
+
action,
|
|
95
127
|
identifier: this.identifier,
|
|
96
128
|
success: () => {
|
|
97
129
|
this.handleReadItNow();
|
|
98
130
|
},
|
|
131
|
+
error: data => {
|
|
132
|
+
this.dispatchActionError(action, data);
|
|
133
|
+
},
|
|
99
134
|
});
|
|
100
135
|
}
|
|
101
136
|
|
|
102
137
|
handleReturnIt() {
|
|
138
|
+
const action = 'return_loan';
|
|
139
|
+
this.dispatchToggleActionGroup();
|
|
140
|
+
|
|
103
141
|
ActionsHandlerService({
|
|
104
|
-
action
|
|
142
|
+
action,
|
|
105
143
|
identifier: this.identifier,
|
|
106
144
|
success: () => {
|
|
107
145
|
this.deleteLoanCookies();
|
|
108
146
|
URLHelper.goToUrl(`/details/${this.identifier}`, true);
|
|
109
147
|
},
|
|
148
|
+
error: data => {
|
|
149
|
+
this.dispatchActionError(action, data);
|
|
150
|
+
},
|
|
110
151
|
});
|
|
111
152
|
}
|
|
112
153
|
|
|
113
154
|
handleBorrowIt() {
|
|
155
|
+
const action = 'borrow_book';
|
|
156
|
+
this.dispatchToggleActionGroup();
|
|
157
|
+
|
|
114
158
|
ActionsHandlerService({
|
|
115
|
-
action
|
|
159
|
+
action,
|
|
116
160
|
identifier: this.identifier,
|
|
117
161
|
success: () => {
|
|
118
162
|
this.handleReadItNow();
|
|
119
163
|
},
|
|
164
|
+
error: data => {
|
|
165
|
+
this.dispatchActionError(action, data);
|
|
166
|
+
},
|
|
120
167
|
});
|
|
121
168
|
}
|
|
122
169
|
|
|
123
170
|
handleReserveIt() {
|
|
171
|
+
const action = 'join_waitlist';
|
|
172
|
+
this.dispatchToggleActionGroup();
|
|
173
|
+
|
|
124
174
|
ActionsHandlerService({
|
|
125
|
-
action
|
|
175
|
+
action,
|
|
126
176
|
identifier: this.identifier,
|
|
127
177
|
success: () => {
|
|
128
178
|
URLHelper.goToUrl(URLHelper.getRedirectUrl(), true);
|
|
129
179
|
},
|
|
180
|
+
error: data => {
|
|
181
|
+
this.dispatchActionError(action, data);
|
|
182
|
+
},
|
|
130
183
|
});
|
|
131
184
|
}
|
|
132
185
|
|
|
133
186
|
handleRemoveFromWaitingList() {
|
|
187
|
+
const action = 'leave_waitlist';
|
|
188
|
+
this.dispatchToggleActionGroup();
|
|
189
|
+
|
|
134
190
|
ActionsHandlerService({
|
|
135
|
-
action
|
|
191
|
+
action,
|
|
136
192
|
identifier: this.identifier,
|
|
137
193
|
success: () => {
|
|
138
194
|
URLHelper.goToUrl(URLHelper.getRedirectUrl(), true);
|
|
139
195
|
},
|
|
196
|
+
error: data => {
|
|
197
|
+
this.dispatchActionError(action, data);
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
handleLoanTokenPoller() {
|
|
203
|
+
const action = 'create_token';
|
|
204
|
+
ActionsHandlerService({
|
|
205
|
+
identifier: this.identifier,
|
|
206
|
+
action,
|
|
207
|
+
error: data => {
|
|
208
|
+
this.dispatchActionError(action, data);
|
|
209
|
+
clearInterval(this.loanTokenInterval); // stop token fetch api
|
|
210
|
+
},
|
|
140
211
|
});
|
|
141
212
|
}
|
|
142
213
|
|
|
214
|
+
dispatchActionError(action, data = {}) {
|
|
215
|
+
this.dispatchEvent(
|
|
216
|
+
new CustomEvent('lendingActionError', {
|
|
217
|
+
detail: { action, data },
|
|
218
|
+
})
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
dispatchToggleActionGroup() {
|
|
223
|
+
this.dispatchEvent(new CustomEvent('toggleActionGroup'));
|
|
224
|
+
}
|
|
225
|
+
|
|
143
226
|
handleLoginOk() {
|
|
144
227
|
/* eslint class-methods-use-this: "off" */
|
|
145
228
|
const target = `/account/login?referer=${encodeURIComponent(
|
|
@@ -172,6 +255,23 @@ export default class ActionsHandler extends LitElement {
|
|
|
172
255
|
}, this.ajaxTimeout);
|
|
173
256
|
}
|
|
174
257
|
|
|
258
|
+
// save consecutive loan count for borrow
|
|
259
|
+
setConsecutiveLoanCounts(action = '') {
|
|
260
|
+
const { localStorage } = window;
|
|
261
|
+
if (localStorage) {
|
|
262
|
+
let newCount = 1;
|
|
263
|
+
const storageKey = `consecutive-loan-count`;
|
|
264
|
+
const existingCount = Number(localStorage.getItem(storageKey));
|
|
265
|
+
|
|
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;
|
|
270
|
+
}
|
|
271
|
+
localStorage.setItem(storageKey, newCount);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
175
275
|
deleteLoanCookies() {
|
|
176
276
|
const date = new Date();
|
|
177
277
|
date.setTime(date.getTime() - 24 * 60 * 60 * 1000); // one day ago
|
|
@@ -75,7 +75,9 @@ export default class GetLendingActions {
|
|
|
75
75
|
const disableBorrow = lendingStatus.loanCount >= lendingStatus.maxLoans;
|
|
76
76
|
|
|
77
77
|
let primaryTitleText = '';
|
|
78
|
-
|
|
78
|
+
let isBrowsing =
|
|
79
|
+
lendingStatus.user_has_browsed && !lendingStatus.browsingExpired;
|
|
80
|
+
if (isBrowsing) {
|
|
79
81
|
primaryTitleText = this.getBrowseCountdownTitle();
|
|
80
82
|
} else {
|
|
81
83
|
primaryTitleText = `Your loan of this book has ${lendingStatus.daysLeftOnLoan} days left.`;
|
|
@@ -94,6 +96,7 @@ export default class GetLendingActions {
|
|
|
94
96
|
this.actionsConfig.adminAccessConfig(),
|
|
95
97
|
this.actionsConfig.purchaseConfig(),
|
|
96
98
|
],
|
|
99
|
+
borrowType: isBrowsing ? 'browsing' : 'borrowing',
|
|
97
100
|
};
|
|
98
101
|
}
|
|
99
102
|
|
package/src/ia-book-actions.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { html, css, LitElement } from 'lit-element';
|
|
3
3
|
|
|
4
4
|
import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
|
|
5
|
+
import { ModalConfig } from '@internetarchive/modal-manager';
|
|
5
6
|
|
|
6
7
|
import './components/collapsible-action-group.js';
|
|
7
8
|
import './components/book-title-bar.js';
|
|
@@ -22,6 +23,7 @@ export default class IABookActions extends LitElement {
|
|
|
22
23
|
bwbPurchaseUrl: { type: String },
|
|
23
24
|
barType: { type: String },
|
|
24
25
|
sharedObserver: { attribute: false },
|
|
26
|
+
disableActionGroup: { type: Boolean },
|
|
25
27
|
};
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -40,6 +42,7 @@ export default class IABookActions extends LitElement {
|
|
|
40
42
|
this.primaryColor = 'primary';
|
|
41
43
|
this.secondaryActions = [];
|
|
42
44
|
this.lendingOptions = {};
|
|
45
|
+
this.disableActionGroup = false;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
disconnectedCallback() {
|
|
@@ -51,6 +54,7 @@ export default class IABookActions extends LitElement {
|
|
|
51
54
|
this.sharedObserver = new SharedResizeObserver();
|
|
52
55
|
this.setupResizeObserver();
|
|
53
56
|
}
|
|
57
|
+
|
|
54
58
|
this.setupLendingToolbarActions();
|
|
55
59
|
}
|
|
56
60
|
|
|
@@ -67,8 +71,7 @@ export default class IABookActions extends LitElement {
|
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
browseHasExpired() {
|
|
70
|
-
const
|
|
71
|
-
const currStatus = { ...this.lendingStatus, browsingExpired };
|
|
74
|
+
const currStatus = { ...this.lendingStatus, browsingExpired: true };
|
|
72
75
|
this.lendingStatus = currStatus;
|
|
73
76
|
}
|
|
74
77
|
|
|
@@ -140,10 +143,10 @@ export default class IABookActions extends LitElement {
|
|
|
140
143
|
return action != null;
|
|
141
144
|
});
|
|
142
145
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
this.borrowType = actions.borrowType;
|
|
147
|
+
if (this.borrowType === 'browsing') {
|
|
148
|
+
// start timer for browsing.
|
|
149
|
+
// when browse is completed, we shows browse-again button
|
|
147
150
|
this.startBrowseTimer();
|
|
148
151
|
}
|
|
149
152
|
}
|
|
@@ -172,13 +175,97 @@ export default class IABookActions extends LitElement {
|
|
|
172
175
|
.primaryActions=${this.primaryActions}
|
|
173
176
|
.secondaryActions=${this.secondaryActions}
|
|
174
177
|
.width=${this.width}
|
|
175
|
-
.
|
|
178
|
+
.borrowType=${this.borrowType}
|
|
179
|
+
?hasAdminAccess=${this.hasAdminAccess}
|
|
180
|
+
?disabled=${this.disableActionGroup}
|
|
181
|
+
@lendingActionError=${this.handleLendingActionError}
|
|
182
|
+
@toggleActionGroup=${this.handleToggleActionGroup}
|
|
176
183
|
>
|
|
177
184
|
</collapsible-action-group>
|
|
178
185
|
${this.textGroupTemplate} ${this.infoIconTemplate}
|
|
179
186
|
`;
|
|
180
187
|
}
|
|
181
188
|
|
|
189
|
+
/*
|
|
190
|
+
* custom event handler to toggle action group visibility
|
|
191
|
+
*
|
|
192
|
+
* @event IABookActions#toggleActionGroup
|
|
193
|
+
*/
|
|
194
|
+
handleToggleActionGroup() {
|
|
195
|
+
this.disableActionGroup = !this.disableActionGroup;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/*
|
|
199
|
+
* handle lending errors occure during different operation like
|
|
200
|
+
* browse book, borrow book, borrowed book token etc...
|
|
201
|
+
*
|
|
202
|
+
* @event IABookActions#lendingActionError
|
|
203
|
+
* @param {Object} event - The employee who is responsible for the project
|
|
204
|
+
* @param {string} event.detail.action - action when error occurred like 'browseBook', 'borrowBook'
|
|
205
|
+
* @param {string} event.detail.data.error - error message
|
|
206
|
+
*/
|
|
207
|
+
handleLendingActionError(event) {
|
|
208
|
+
// toggle activity loader
|
|
209
|
+
this.handleToggleActionGroup();
|
|
210
|
+
|
|
211
|
+
const action = event?.detail?.action;
|
|
212
|
+
const errorMsg = event?.detail?.data?.error;
|
|
213
|
+
|
|
214
|
+
if (errorMsg) this.showErrorModal(errorMsg, action);
|
|
215
|
+
|
|
216
|
+
// update action bar state if book is not available to browse or borrow.
|
|
217
|
+
if (errorMsg && errorMsg.match(/not available to borrow/gm)) {
|
|
218
|
+
let currStatus = this.lendingStatus;
|
|
219
|
+
if (action === 'browse_book') {
|
|
220
|
+
currStatus = {
|
|
221
|
+
...this.lendingStatus,
|
|
222
|
+
available_to_browse: false,
|
|
223
|
+
};
|
|
224
|
+
} else if (action === 'borrow_book') {
|
|
225
|
+
currStatus = {
|
|
226
|
+
...this.lendingStatus,
|
|
227
|
+
available_to_borrow: false,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
this.lendingStatus = currStatus;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* show error message if something went wrong */
|
|
235
|
+
async showErrorModal(errorMsg, action) {
|
|
236
|
+
this.disableActionGroup = false;
|
|
237
|
+
|
|
238
|
+
this.modal = document.querySelector('#action-bar-modal');
|
|
239
|
+
if (!this.modal) {
|
|
240
|
+
this.modal = document.createElement('modal-manager');
|
|
241
|
+
this.modal.id = 'action-bar-modal';
|
|
242
|
+
}
|
|
243
|
+
await document.body.appendChild(this.modal);
|
|
244
|
+
|
|
245
|
+
const modalConfig = new ModalConfig({
|
|
246
|
+
title: 'Lending error',
|
|
247
|
+
message: errorMsg,
|
|
248
|
+
headerColor: '#d9534f',
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
if (action === 'create_token') {
|
|
252
|
+
modalConfig.closeOnBackdropClick = false;
|
|
253
|
+
modalConfig.showCloseButton = false;
|
|
254
|
+
modalConfig.message = html` Uh oh, something went wrong trying to access
|
|
255
|
+
this book.<br />
|
|
256
|
+
Please <a href="/">refresh</a> to try again or send us an email to
|
|
257
|
+
<a
|
|
258
|
+
href="mailto:info@archive.org?subject=Help: cannot access my borrowed book: ${this
|
|
259
|
+
.identifier}"
|
|
260
|
+
>info@archive.org</a
|
|
261
|
+
>`;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
this.modal.showModal({
|
|
265
|
+
config: modalConfig,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
182
269
|
get iconClass() {
|
|
183
270
|
return this.width <= mobileContainerWidth ? 'mobile' : 'desktop';
|
|
184
271
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { html, fixture, expect } from '@open-wc/testing';
|
|
2
2
|
import '../../src/components/collapsible-action-group.js';
|
|
3
|
+
import Sinon from 'sinon';
|
|
3
4
|
|
|
4
5
|
const container = ({
|
|
5
6
|
primaryActions = [
|
|
@@ -23,10 +24,12 @@ const container = ({
|
|
|
23
24
|
text: 'Purchase',
|
|
24
25
|
},
|
|
25
26
|
],
|
|
27
|
+
borrowType = '',
|
|
26
28
|
} = {}) =>
|
|
27
29
|
html`<collapsible-action-group
|
|
28
30
|
.primaryActions=${primaryActions}
|
|
29
31
|
.secondaryActions=${secondaryActions}
|
|
32
|
+
.borrowType=${borrowType}
|
|
30
33
|
></collapsible-action-group>`;
|
|
31
34
|
|
|
32
35
|
describe('<collapsible-action-group>', () => {
|
|
@@ -39,6 +42,22 @@ describe('<collapsible-action-group>', () => {
|
|
|
39
42
|
const primaryButton = primaryActionContainer.querySelector('.ia-button');
|
|
40
43
|
expect(primaryButton.innerText).to.equal('Borrow for 1 hour');
|
|
41
44
|
});
|
|
45
|
+
|
|
46
|
+
it('check if loader is active and action-group is disabled', async () => {
|
|
47
|
+
const el = await fixture(container());
|
|
48
|
+
|
|
49
|
+
const primaryActionContainer = el.shadowRoot.querySelector('.primary');
|
|
50
|
+
primaryActionContainer
|
|
51
|
+
.querySelector('.ia-button')
|
|
52
|
+
.dispatchEvent(new CustomEvent('toggle-loader'));
|
|
53
|
+
el.disabled = true;
|
|
54
|
+
await el.updateComplete;
|
|
55
|
+
|
|
56
|
+
expect(el.disabled).to.be.true;
|
|
57
|
+
expect(el.shadowRoot.querySelector('div').classList.contains('disabled')).to
|
|
58
|
+
.be.true;
|
|
59
|
+
});
|
|
60
|
+
|
|
42
61
|
it('fires analytics events', async () => {
|
|
43
62
|
const el = await fixture(container());
|
|
44
63
|
const primaryActionContainer = el.shadowRoot.querySelector('.primary');
|
|
@@ -66,3 +85,27 @@ describe('<collapsible-action-group>', () => {
|
|
|
66
85
|
expect(eAnalytics.action).to.equal('Browse');
|
|
67
86
|
});
|
|
68
87
|
});
|
|
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
|
+
});
|
|
@@ -106,6 +106,64 @@ describe('Primary Actions data', () => {
|
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
describe('Borrow status actions', () => {
|
|
109
|
+
it('Update available_to_browse key when book is not available to borrow', async () => {
|
|
110
|
+
const el = await fixture(
|
|
111
|
+
container({
|
|
112
|
+
userid: '@user1',
|
|
113
|
+
lendingStatus: {
|
|
114
|
+
is_lendable: true,
|
|
115
|
+
available_to_browse: true,
|
|
116
|
+
available_to_borrow: true,
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const errorEvent = new CustomEvent('lendingActionError');
|
|
122
|
+
el.addEventListener('lendingActionError', () => {
|
|
123
|
+
el.handleLendingActionError({
|
|
124
|
+
detail: {
|
|
125
|
+
action: 'browse_book',
|
|
126
|
+
data: { error: 'not available to borrow' },
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
el.dispatchEvent(errorEvent);
|
|
131
|
+
await el.updateComplete;
|
|
132
|
+
|
|
133
|
+
// removed available_to_browse from lending bar
|
|
134
|
+
expect(el.lendingStatus.available_to_browse).to.be.false;
|
|
135
|
+
expect(el.primaryActions[0].text).to.equal('Borrow for 14 days');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('Update available_to_borrow key when book is not available to borrow', async () => {
|
|
139
|
+
const el = await fixture(
|
|
140
|
+
container({
|
|
141
|
+
userid: '@user1',
|
|
142
|
+
lendingStatus: {
|
|
143
|
+
is_lendable: true,
|
|
144
|
+
available_to_browse: true,
|
|
145
|
+
available_to_borrow: true,
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const errorEvent = new Event('lendingActionError');
|
|
151
|
+
el.addEventListener('lendingActionError', () => {
|
|
152
|
+
el.handleLendingActionError({
|
|
153
|
+
detail: {
|
|
154
|
+
action: 'borrow_book',
|
|
155
|
+
data: { error: 'not available to borrow' },
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
el.dispatchEvent(errorEvent);
|
|
160
|
+
await el.updateComplete;
|
|
161
|
+
|
|
162
|
+
// removed available_to_borrow from lending bar
|
|
163
|
+
expect(el.lendingStatus.available_to_borrow).to.be.false;
|
|
164
|
+
expect(el.primaryActions[0].text).to.equal('Borrow for 1 hour');
|
|
165
|
+
});
|
|
166
|
+
|
|
109
167
|
it('Check action for borrowable book without user', async () => {
|
|
110
168
|
const el = await fixture(
|
|
111
169
|
container({
|