@internetarchive/ia-book-actions 0.0.6 → 0.0.7-10
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 +47 -2
- package/package.json +4 -1
- package/src/assets/styles/collapsible-action-group.js +10 -2
- package/src/components/collapsible-action-group.js +32 -15
- package/src/core/services/actions-handler/actions-handler-service.js +39 -29
- package/src/core/services/actions-handler/actions-handler.js +101 -12
- package/src/core/services/get-lending-actions.js +4 -1
- package/src/core/services/loan-token-poller.js +103 -0
- package/src/ia-book-actions.js +129 -15
- package/test/components/collapsible-action-group.test.js +18 -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,23 @@
|
|
|
92
101
|
|
|
93
102
|
let iaBookActions = document.querySelector('ia-book-actions');
|
|
94
103
|
|
|
104
|
+
const modalConfig = new ModalConfig();
|
|
105
|
+
modalConfig.headerColor = '#d9534f';
|
|
106
|
+
|
|
107
|
+
let lendingBarPostInit = function lendingBarPostInit() {
|
|
108
|
+
setTimeout(function() {
|
|
109
|
+
console.log('executed');
|
|
110
|
+
}, 100);
|
|
111
|
+
}
|
|
95
112
|
// set defaultLendingStatus for unavailable (without borrowables) book
|
|
96
|
-
iaBookActions.userid =
|
|
113
|
+
iaBookActions.userid = userid;
|
|
97
114
|
iaBookActions.identifier = identifier;
|
|
98
115
|
iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
|
|
99
|
-
iaBookActions.lendingStatus =
|
|
116
|
+
iaBookActions.lendingStatus = canBrowseAndBorrow;
|
|
100
117
|
iaBookActions.bwbPurchaseUrl = '';
|
|
101
118
|
iaBookActions.barType = '';
|
|
119
|
+
iaBookActions.modalConfig = modalConfig;
|
|
120
|
+
iaBookActions.lendingBarPostInit = lendingBarPostInit;
|
|
102
121
|
|
|
103
122
|
let lendingStatus1 = iaBookActions.lendingStatus;
|
|
104
123
|
|
|
@@ -112,6 +131,29 @@
|
|
|
112
131
|
});
|
|
113
132
|
});
|
|
114
133
|
|
|
134
|
+
document.querySelectorAll('.errorEnable input[type=checkbox]').forEach((item) => {
|
|
135
|
+
if (window.location.href.indexOf('?error=true') !== -1) {
|
|
136
|
+
item.checked = true;
|
|
137
|
+
}
|
|
138
|
+
item.addEventListener('click', (e) => {
|
|
139
|
+
var searchParams = new URLSearchParams(window.location.search);
|
|
140
|
+
var separate = '';
|
|
141
|
+
if (e.target.checked) {
|
|
142
|
+
separate = '?';
|
|
143
|
+
searchParams.set('error', true);
|
|
144
|
+
} else {
|
|
145
|
+
separate = '';
|
|
146
|
+
searchParams.delete('error');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (history.pushState) {
|
|
150
|
+
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + separate + searchParams;
|
|
151
|
+
window.history.pushState({path:newurl},'',newurl);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
|
|
115
157
|
document.querySelectorAll('.userState input[type=checkbox]').forEach((item) => {
|
|
116
158
|
item.addEventListener('click', (e) => {
|
|
117
159
|
if (e.target.checked) {
|
|
@@ -219,6 +261,9 @@
|
|
|
219
261
|
<fieldset>
|
|
220
262
|
<legend>Dev testing for book action bar</legend>
|
|
221
263
|
<table class="initial">
|
|
264
|
+
<tr colspan='5'>
|
|
265
|
+
<td class="errorEnable"><label><input type="checkbox" name="errorEnable" value="errorEnable" />Do you want to see error response?</label></td>
|
|
266
|
+
</tr>
|
|
222
267
|
<tr>
|
|
223
268
|
<td class="userState">
|
|
224
269
|
<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-10",
|
|
4
4
|
"description": "Bookreader actions for borrowable book",
|
|
5
5
|
"author": "Internet Archive",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -20,7 +20,10 @@
|
|
|
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/local-cache": "^0.2.0",
|
|
26
|
+
"@internetarchive/modal-manager": "^0.1.0",
|
|
24
27
|
"@internetarchive/shared-resize-observer": "^0.0.1",
|
|
25
28
|
"lit-element": "^2.4.0",
|
|
26
29
|
"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,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
25
26
|
width: { type: Number },
|
|
26
27
|
hasAdminAccess: { type: Boolean },
|
|
27
28
|
dropdownArrow: { type: String },
|
|
29
|
+
disabled: { type: Boolean },
|
|
28
30
|
};
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -42,13 +44,12 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
42
44
|
this.initialButton = false;
|
|
43
45
|
this.title = '';
|
|
44
46
|
this.loaderIcon = 'https://archive.org/upload/images/tree/loading.gif';
|
|
47
|
+
this.disabled = false;
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
updated(changed) {
|
|
48
|
-
if (changed.has('width')) {
|
|
49
|
-
|
|
50
|
-
this.resetActions();
|
|
51
|
-
}
|
|
51
|
+
if (changed.has('width') && this.isBelowTabletContainer) {
|
|
52
|
+
this.resetActions();
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
|
|
@@ -94,13 +95,20 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
94
95
|
|
|
95
96
|
render() {
|
|
96
97
|
return html`
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
<div
|
|
99
|
+
class="${classMap({
|
|
100
|
+
actiongroup: true,
|
|
101
|
+
disabled: this.disabled,
|
|
102
|
+
})}"
|
|
103
|
+
>
|
|
104
|
+
${this.getLoaderIcon}
|
|
105
|
+
<section class="action-buttons primary">
|
|
106
|
+
${this.renderPrimaryActions}
|
|
107
|
+
</section>
|
|
108
|
+
<section class="action-buttons secondary">
|
|
109
|
+
${this.renderSecondaryActions}
|
|
110
|
+
</section>
|
|
111
|
+
</div>
|
|
104
112
|
`;
|
|
105
113
|
}
|
|
106
114
|
|
|
@@ -177,11 +185,13 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
177
185
|
}
|
|
178
186
|
|
|
179
187
|
/**
|
|
180
|
-
*
|
|
181
|
-
* @param { string } eventName
|
|
182
|
-
* @param { object } gaEvent
|
|
188
|
+
* Dispatches click events when patron clicks on action buttons
|
|
189
|
+
* @param { string } eventName - actions like 'browseBook', 'borrowBook' etc...
|
|
190
|
+
* @param { object } gaEvent - contains analytics event action and category
|
|
183
191
|
* @param { string } gaEvent.category
|
|
184
192
|
* @param { string } gaEvent.action
|
|
193
|
+
*
|
|
194
|
+
* @fires CollapsibleActionGroup#{eventName} - (will be browseBook, borrowBook etc...)
|
|
185
195
|
*/
|
|
186
196
|
clickHandler(eventName, gaEvent) {
|
|
187
197
|
this.dropdownState = 'close';
|
|
@@ -225,7 +235,14 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
225
235
|
* @returns { HTMLElement }
|
|
226
236
|
*/
|
|
227
237
|
get getLoaderIcon() {
|
|
228
|
-
return html`<img
|
|
238
|
+
return html`<img
|
|
239
|
+
class="${classMap({
|
|
240
|
+
actionloader: true,
|
|
241
|
+
disabled: this.disabled,
|
|
242
|
+
})}"
|
|
243
|
+
alt=""
|
|
244
|
+
src="${this.loaderIcon}"
|
|
245
|
+
/>`;
|
|
229
246
|
}
|
|
230
247
|
|
|
231
248
|
/**
|
|
@@ -8,24 +8,20 @@ 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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
// return intentional error on dev environment
|
|
20
|
+
const shouldReturnError =
|
|
21
|
+
location?.href?.indexOf('?error=true') !== -1 &&
|
|
22
|
+
location?.hostname !== 'archive.org';
|
|
23
|
+
|
|
24
|
+
if (location?.pathname === '/demo/') baseHost = `/demo/`;
|
|
29
25
|
|
|
30
26
|
let formData = new FormData();
|
|
31
27
|
formData.append('action', option.action);
|
|
@@ -36,23 +32,37 @@ export default function ActionsHandlerService(options) {
|
|
|
36
32
|
body: formData,
|
|
37
33
|
})
|
|
38
34
|
.then(response => {
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
const tokenError = 'loan token not found. please try again later.';
|
|
36
|
+
const borrowError =
|
|
37
|
+
'This book is not available to borrow at this time. Please try again later.';
|
|
38
|
+
|
|
39
|
+
// return error reponse when not production and has ?error=true param...
|
|
40
|
+
const erroneousActions = ['browse_book', 'borrow_book', 'create_token'];
|
|
41
|
+
if (shouldReturnError && erroneousActions.includes(option?.action)) {
|
|
42
|
+
return {
|
|
43
|
+
success: false,
|
|
44
|
+
error: option?.action === 'create_token' ? tokenError : borrowError,
|
|
45
|
+
};
|
|
41
46
|
}
|
|
42
|
-
})
|
|
43
|
-
.catch(error => {
|
|
44
|
-
console.log(error);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
// return success response for /demo/ server...
|
|
49
|
+
if (baseHost == '/demo/1' || baseHost == '/demo/') {
|
|
50
|
+
return {
|
|
51
|
+
success: true,
|
|
52
|
+
message: 'operation executed successfully!',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
// The response is a Response instance.
|
|
57
|
+
// You parse the data into a useable format using `.json()`
|
|
58
|
+
return response.json();
|
|
59
|
+
})
|
|
60
|
+
.then(data => {
|
|
61
|
+
// `data` is the parsed version of the JSON returned from the above endpoint.
|
|
62
|
+
if (!data?.error) {
|
|
63
|
+
option?.success(data);
|
|
64
|
+
} else {
|
|
65
|
+
option?.error(data);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
58
68
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { LitElement } from 'lit-element';
|
|
2
|
+
import { LocalCache } from '@internetarchive/local-cache';
|
|
3
|
+
|
|
2
4
|
import { URLHelper } from '../../config/url-helper.js';
|
|
3
5
|
import ActionsHandlerService from './actions-handler-service.js';
|
|
4
6
|
|
|
@@ -7,33 +9,39 @@ import ActionsHandlerService from './actions-handler-service.js';
|
|
|
7
9
|
*
|
|
8
10
|
* ActionsHandlerService is a function being used to execute
|
|
9
11
|
* 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.
|
|
12
|
+
* 1. identifier: book name.
|
|
14
13
|
*/
|
|
15
14
|
|
|
16
15
|
export default class ActionsHandler extends LitElement {
|
|
17
16
|
constructor(identifier) {
|
|
18
17
|
super();
|
|
19
18
|
this.identifier = identifier;
|
|
20
|
-
this.ajaxTimeout =
|
|
19
|
+
this.ajaxTimeout = 7000;
|
|
20
|
+
this.localCache = new LocalCache();
|
|
21
21
|
this.bindEvents();
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
sendEvent(eventCategory, eventAction) {
|
|
25
25
|
// eslint-disable-next-line no-console
|
|
26
26
|
console?.log('Book action: ', { eventCategory, eventAction });
|
|
27
|
-
window?.archive_analytics?.
|
|
27
|
+
window?.archive_analytics?.send_event_no_sampling(
|
|
28
28
|
eventCategory,
|
|
29
29
|
eventAction,
|
|
30
|
-
|
|
30
|
+
`identifier=${this.identifier}`
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
bindEvents() {
|
|
35
35
|
this.addEventListener('browseBook', ({ detail }) => {
|
|
36
36
|
this.handleBrowseIt();
|
|
37
|
+
this.setConsecutiveLoanCounts();
|
|
38
|
+
const { category, action } = detail.event;
|
|
39
|
+
this.sendEvent(category, action);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
this.addEventListener('browseBookAgain', ({ detail }) => {
|
|
43
|
+
this.handleBrowseIt();
|
|
44
|
+
this.setConsecutiveLoanCounts('browseAgain');
|
|
37
45
|
const { category, action } = detail.event;
|
|
38
46
|
this.sendEvent(category, action);
|
|
39
47
|
});
|
|
@@ -90,56 +98,114 @@ export default class ActionsHandler extends LitElement {
|
|
|
90
98
|
}
|
|
91
99
|
|
|
92
100
|
handleBrowseIt() {
|
|
101
|
+
const action = 'browse_book';
|
|
102
|
+
this.dispatchToggleActionGroup();
|
|
103
|
+
|
|
93
104
|
ActionsHandlerService({
|
|
94
|
-
action
|
|
105
|
+
action,
|
|
95
106
|
identifier: this.identifier,
|
|
96
107
|
success: () => {
|
|
97
108
|
this.handleReadItNow();
|
|
98
109
|
},
|
|
110
|
+
error: data => {
|
|
111
|
+
this.dispatchActionError(action, data);
|
|
112
|
+
},
|
|
99
113
|
});
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
handleReturnIt() {
|
|
117
|
+
const action = 'return_loan';
|
|
118
|
+
this.dispatchToggleActionGroup();
|
|
119
|
+
|
|
103
120
|
ActionsHandlerService({
|
|
104
|
-
action
|
|
121
|
+
action,
|
|
105
122
|
identifier: this.identifier,
|
|
106
123
|
success: () => {
|
|
107
124
|
this.deleteLoanCookies();
|
|
108
125
|
URLHelper.goToUrl(`/details/${this.identifier}`, true);
|
|
109
126
|
},
|
|
127
|
+
error: data => {
|
|
128
|
+
this.dispatchActionError(action, data);
|
|
129
|
+
},
|
|
110
130
|
});
|
|
111
131
|
}
|
|
112
132
|
|
|
113
133
|
handleBorrowIt() {
|
|
134
|
+
const action = 'borrow_book';
|
|
135
|
+
this.dispatchToggleActionGroup();
|
|
136
|
+
|
|
114
137
|
ActionsHandlerService({
|
|
115
|
-
action
|
|
138
|
+
action,
|
|
116
139
|
identifier: this.identifier,
|
|
117
140
|
success: () => {
|
|
118
141
|
this.handleReadItNow();
|
|
119
142
|
},
|
|
143
|
+
error: data => {
|
|
144
|
+
this.dispatchActionError(action, data);
|
|
145
|
+
},
|
|
120
146
|
});
|
|
121
147
|
}
|
|
122
148
|
|
|
123
149
|
handleReserveIt() {
|
|
150
|
+
const action = 'join_waitlist';
|
|
151
|
+
this.dispatchToggleActionGroup();
|
|
152
|
+
|
|
124
153
|
ActionsHandlerService({
|
|
125
|
-
action
|
|
154
|
+
action,
|
|
126
155
|
identifier: this.identifier,
|
|
127
156
|
success: () => {
|
|
128
157
|
URLHelper.goToUrl(URLHelper.getRedirectUrl(), true);
|
|
129
158
|
},
|
|
159
|
+
error: data => {
|
|
160
|
+
this.dispatchActionError(action, data);
|
|
161
|
+
},
|
|
130
162
|
});
|
|
131
163
|
}
|
|
132
164
|
|
|
133
165
|
handleRemoveFromWaitingList() {
|
|
166
|
+
const action = 'leave_waitlist';
|
|
167
|
+
this.dispatchToggleActionGroup();
|
|
168
|
+
|
|
134
169
|
ActionsHandlerService({
|
|
135
|
-
action
|
|
170
|
+
action,
|
|
136
171
|
identifier: this.identifier,
|
|
137
172
|
success: () => {
|
|
138
173
|
URLHelper.goToUrl(URLHelper.getRedirectUrl(), true);
|
|
139
174
|
},
|
|
175
|
+
error: data => {
|
|
176
|
+
this.dispatchActionError(action, data);
|
|
177
|
+
},
|
|
140
178
|
});
|
|
141
179
|
}
|
|
142
180
|
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Dispatches event when an error occured on action
|
|
184
|
+
* Notes:- toggle <collapsible-action-group> visibility (enable/disable).
|
|
185
|
+
*
|
|
186
|
+
* @param { String } action - name of action like browse_book, borrow_book
|
|
187
|
+
* @param { Object } data - erroneous response from api call
|
|
188
|
+
*
|
|
189
|
+
* @fires ActionsHandler#lendingActionError
|
|
190
|
+
*/
|
|
191
|
+
dispatchActionError(action, data = {}) {
|
|
192
|
+
this.dispatchEvent(
|
|
193
|
+
new CustomEvent('lendingActionError', {
|
|
194
|
+
detail: { action, data },
|
|
195
|
+
})
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Dispatches event when patron is clicked on action buttons.
|
|
201
|
+
* Notes:- toggle <collapsible-action-group> disable/enable.
|
|
202
|
+
*
|
|
203
|
+
* @fires ActionsHandler#toggleActionGroup
|
|
204
|
+
*/
|
|
205
|
+
dispatchToggleActionGroup() {
|
|
206
|
+
this.dispatchEvent(new CustomEvent('toggleActionGroup'));
|
|
207
|
+
}
|
|
208
|
+
|
|
143
209
|
handleLoginOk() {
|
|
144
210
|
/* eslint class-methods-use-this: "off" */
|
|
145
211
|
const target = `/account/login?referer=${encodeURIComponent(
|
|
@@ -172,6 +238,29 @@ export default class ActionsHandler extends LitElement {
|
|
|
172
238
|
}, this.ajaxTimeout);
|
|
173
239
|
}
|
|
174
240
|
|
|
241
|
+
// save consecutive loan count for borrow
|
|
242
|
+
async setConsecutiveLoanCounts(action = '') {
|
|
243
|
+
try {
|
|
244
|
+
let newCount = 1;
|
|
245
|
+
const storageKey = `consecutive-loan-count`;
|
|
246
|
+
const existingCount = await this.localCache.get(storageKey);
|
|
247
|
+
|
|
248
|
+
// increase browse-count by 1 when you consecutive reading a book.
|
|
249
|
+
if (action === 'browseAgain' && existingCount !== undefined) {
|
|
250
|
+
newCount = existingCount ? existingCount + 1 : 1;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// set new value
|
|
254
|
+
await this.localCache.set({
|
|
255
|
+
key: storageKey,
|
|
256
|
+
value: newCount,
|
|
257
|
+
ttl: 7200, // 2 hours
|
|
258
|
+
});
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.log(error);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
175
264
|
deleteLoanCookies() {
|
|
176
265
|
const date = new Date();
|
|
177
266
|
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 ? 'browsed' : 'borrowed',
|
|
97
100
|
};
|
|
98
101
|
}
|
|
99
102
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { LitElement } from 'lit-element';
|
|
2
|
+
import { LocalCache } from '@internetarchive/local-cache';
|
|
3
|
+
|
|
4
|
+
import ActionsHandlerService from './actions-handler/actions-handler-service.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This class is used to create loan token for borrowed books
|
|
8
|
+
*
|
|
9
|
+
* ActionsHandlerService is a function being used to execute
|
|
10
|
+
*/
|
|
11
|
+
export class LoanTokenPoller extends LitElement {
|
|
12
|
+
constructor() {
|
|
13
|
+
super();
|
|
14
|
+
this.identifier = '';
|
|
15
|
+
this.loanTokenPollingDelay = window.location.pathname === '/demo/' ? 2000 : 120000; // 120000 ms = 2 min
|
|
16
|
+
this.loanTokenInterval = undefined;
|
|
17
|
+
this.localCache = new LocalCache();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
disconnectedCallback() {
|
|
21
|
+
this.loanTokenInterval = undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async enableBookAccess(identifier, borrowType) {
|
|
25
|
+
this.identifier = identifier
|
|
26
|
+
let consecutiveLoanCounts = 1;
|
|
27
|
+
|
|
28
|
+
if (borrowType) {
|
|
29
|
+
// send consecutiveLoanCounts for browsed books only.
|
|
30
|
+
if (borrowType === 'browsed') {
|
|
31
|
+
try {
|
|
32
|
+
const existingCount = await this.localCache.get(
|
|
33
|
+
'consecutive-loan-count'
|
|
34
|
+
);
|
|
35
|
+
consecutiveLoanCounts = existingCount ?? 1;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.log(error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Do an initial token, then set an interval
|
|
42
|
+
this.handleLoanTokenPoller();
|
|
43
|
+
|
|
44
|
+
this.loanTokenInterval = setInterval(() => {
|
|
45
|
+
this.handleLoanTokenPoller();
|
|
46
|
+
}, this.loanTokenPollingDelay);
|
|
47
|
+
|
|
48
|
+
// event category and action for browsing book access
|
|
49
|
+
const category = `${borrowType}BookAccess`;
|
|
50
|
+
const action = `${
|
|
51
|
+
borrowType === 'browsed' ? 'BrowseCounts-' : 'Counts-'
|
|
52
|
+
}${consecutiveLoanCounts}`;
|
|
53
|
+
console.log(consecutiveLoanCounts)
|
|
54
|
+
this.sendEvent(category, action);
|
|
55
|
+
} else {
|
|
56
|
+
// if book is not browsed, just clear token polling interval
|
|
57
|
+
clearInterval(this.loanTokenInterval);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
sendEvent(eventCategory, eventAction) {
|
|
62
|
+
// eslint-disable-next-line no-console
|
|
63
|
+
console?.log('Book action: ', { eventCategory, eventAction });
|
|
64
|
+
window?.archive_analytics?.send_event_no_sampling(
|
|
65
|
+
eventCategory,
|
|
66
|
+
eventAction,
|
|
67
|
+
`identifier=${this.identifier}`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async handleLoanTokenPoller() {
|
|
72
|
+
const action = 'create_token';
|
|
73
|
+
// await new Promise(r => setTimeout(r, 3000));
|
|
74
|
+
ActionsHandlerService({
|
|
75
|
+
identifier: this.identifier,
|
|
76
|
+
action,
|
|
77
|
+
error: data => {
|
|
78
|
+
console.log('error', data);
|
|
79
|
+
this.handleLendingActionError({detail: { action, data }})
|
|
80
|
+
// this.dispatchActionError(action, data);
|
|
81
|
+
clearInterval(this.loanTokenInterval); // stop token fetch api
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Dispatches event when an error occured on action
|
|
88
|
+
* Notes:- toggle <collapsible-action-group> visibility (enable/disable).
|
|
89
|
+
*
|
|
90
|
+
* @param { String } action - name of action like browse_book, borrow_book
|
|
91
|
+
* @param { Object } data - erroneous response from api call
|
|
92
|
+
*
|
|
93
|
+
* @fires ActionsHandler#lendingActionError
|
|
94
|
+
*/
|
|
95
|
+
dispatchActionError(action, data = {}) {
|
|
96
|
+
console.log('disptaced');
|
|
97
|
+
this.dispatchEvent(
|
|
98
|
+
new CustomEvent('lendingActionError', {
|
|
99
|
+
detail: { action, data },
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
package/src/ia-book-actions.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/* eslint-disable camelcase */
|
|
2
|
-
import { html, css
|
|
2
|
+
import { html, css } 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';
|
|
@@ -10,8 +11,9 @@ import './components/info-icon.js';
|
|
|
10
11
|
|
|
11
12
|
import GetLendingActions from './core/services/get-lending-actions.js';
|
|
12
13
|
import { mobileContainerWidth } from './core/config/constants.js';
|
|
14
|
+
import { LoanTokenPoller } from './core/services/loan-token-poller.js';
|
|
13
15
|
|
|
14
|
-
export default class IABookActions extends
|
|
16
|
+
export default class IABookActions extends LoanTokenPoller {
|
|
15
17
|
static get properties() {
|
|
16
18
|
return {
|
|
17
19
|
userid: { type: String },
|
|
@@ -20,8 +22,11 @@ export default class IABookActions extends LitElement {
|
|
|
20
22
|
lendingStatus: { type: Object },
|
|
21
23
|
width: { type: Number },
|
|
22
24
|
bwbPurchaseUrl: { type: String },
|
|
25
|
+
lendingBarPostInit: { type: Function },
|
|
23
26
|
barType: { type: String },
|
|
24
27
|
sharedObserver: { attribute: false },
|
|
28
|
+
disableActionGroup: { type: Boolean },
|
|
29
|
+
modal: { Object },
|
|
25
30
|
};
|
|
26
31
|
}
|
|
27
32
|
|
|
@@ -33,13 +38,20 @@ export default class IABookActions extends LitElement {
|
|
|
33
38
|
this.lendingStatus = {};
|
|
34
39
|
this.width = 0;
|
|
35
40
|
this.bwbPurchaseUrl = '';
|
|
41
|
+
this.lendingBarPostInit = () => {};
|
|
36
42
|
this.barType = 'action'; // 'title'|'action'
|
|
37
43
|
this.sharedObserver = undefined;
|
|
44
|
+
this.disableActionGroup = false;
|
|
45
|
+
this.modal = undefined;
|
|
46
|
+
|
|
47
|
+
// private props
|
|
38
48
|
this.primaryActions = [];
|
|
39
49
|
this.primaryTitle = '';
|
|
40
50
|
this.primaryColor = 'primary';
|
|
41
51
|
this.secondaryActions = [];
|
|
42
52
|
this.lendingOptions = {};
|
|
53
|
+
this.borrowType = ''; // (browsed|borrowed)
|
|
54
|
+
this.consecutiveLoanCounts = 1; // consecutive loan count
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
disconnectedCallback() {
|
|
@@ -51,10 +63,10 @@ export default class IABookActions extends LitElement {
|
|
|
51
63
|
this.sharedObserver = new SharedResizeObserver();
|
|
52
64
|
this.setupResizeObserver();
|
|
53
65
|
}
|
|
54
|
-
this.setupLendingToolbarActions();
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
updated(changed) {
|
|
69
|
+
console.log(changed)
|
|
58
70
|
if (changed.has('lendingStatus') || changed.has('bwbPurchaseUrl')) {
|
|
59
71
|
this.setupLendingToolbarActions();
|
|
60
72
|
this.update();
|
|
@@ -67,8 +79,7 @@ export default class IABookActions extends LitElement {
|
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
browseHasExpired() {
|
|
70
|
-
const
|
|
71
|
-
const currStatus = { ...this.lendingStatus, browsingExpired };
|
|
82
|
+
const currStatus = { ...this.lendingStatus, browsingExpired: true };
|
|
72
83
|
this.lendingStatus = currStatus;
|
|
73
84
|
}
|
|
74
85
|
|
|
@@ -140,20 +151,34 @@ export default class IABookActions extends LitElement {
|
|
|
140
151
|
return action != null;
|
|
141
152
|
});
|
|
142
153
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
154
|
+
this.borrowType = actions.borrowType;
|
|
155
|
+
if (this.borrowType === 'browsed') {
|
|
156
|
+
// start timer for browsed.
|
|
157
|
+
// when browse is completed, we shows browse-again button
|
|
147
158
|
this.startBrowseTimer();
|
|
148
159
|
}
|
|
160
|
+
|
|
161
|
+
console.log('this.borrowType', this.borrowType);
|
|
162
|
+
// enable access of borrowed/browsed books
|
|
163
|
+
if (this.borrowType) {
|
|
164
|
+
await this.enableBookAccess(this.identifier, this.borrowType);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* this callback function use to:-
|
|
169
|
+
* - disptach lenfingFlow::PostInit event
|
|
170
|
+
* - initialize bookreader using br.init()
|
|
171
|
+
*/
|
|
172
|
+
console.log(this.lendingBarPostInit);
|
|
173
|
+
this.lendingBarPostInit();
|
|
149
174
|
}
|
|
150
175
|
|
|
151
176
|
render() {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
177
|
+
if (this.barType === 'title') {
|
|
178
|
+
return html`<section class="lending-wrapper">${this.bookTitleBar}</section>`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return html`<section class="lending-wrapper">${this.bookActionBar}</section>`;
|
|
157
182
|
}
|
|
158
183
|
|
|
159
184
|
get bookTitleBar() {
|
|
@@ -172,13 +197,102 @@ export default class IABookActions extends LitElement {
|
|
|
172
197
|
.primaryActions=${this.primaryActions}
|
|
173
198
|
.secondaryActions=${this.secondaryActions}
|
|
174
199
|
.width=${this.width}
|
|
175
|
-
.
|
|
200
|
+
.borrowType=${this.borrowType}
|
|
201
|
+
?hasAdminAccess=${this.hasAdminAccess}
|
|
202
|
+
?disabled=${this.disableActionGroup}
|
|
203
|
+
@lendingActionError=${this.handleLendingActionError}
|
|
204
|
+
@toggleActionGroup=${this.handleToggleActionGroup}
|
|
176
205
|
>
|
|
177
206
|
</collapsible-action-group>
|
|
178
207
|
${this.textGroupTemplate} ${this.infoIconTemplate}
|
|
179
208
|
`;
|
|
180
209
|
}
|
|
181
210
|
|
|
211
|
+
/*
|
|
212
|
+
* custom event handler to toggle action group visibility
|
|
213
|
+
*
|
|
214
|
+
* @event IABookActions#toggleActionGroup
|
|
215
|
+
*/
|
|
216
|
+
handleToggleActionGroup() {
|
|
217
|
+
this.disableActionGroup = !this.disableActionGroup;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/*
|
|
221
|
+
* handle lending errors occure during different operation like
|
|
222
|
+
* browse book, borrow book, borrowed book token etc...
|
|
223
|
+
*
|
|
224
|
+
* @event IABookActions#lendingActionError
|
|
225
|
+
* @param {Object} event - The employee who is responsible for the project
|
|
226
|
+
* @param {string} event.detail.action - action when error occurred like 'browseBook', 'borrowBook'
|
|
227
|
+
* @param {string} event.detail.data.error - error message
|
|
228
|
+
*/
|
|
229
|
+
handleLendingActionError(event) {
|
|
230
|
+
// toggle activity loader
|
|
231
|
+
this.handleToggleActionGroup();
|
|
232
|
+
|
|
233
|
+
const action = event?.detail?.action;
|
|
234
|
+
const errorMsg = event?.detail?.data?.error;
|
|
235
|
+
|
|
236
|
+
if (errorMsg) this.showErrorModal(errorMsg, action);
|
|
237
|
+
|
|
238
|
+
// update action bar state if book is not available to browse or borrow.
|
|
239
|
+
if (errorMsg && errorMsg.match(/not available to borrow/gm)) {
|
|
240
|
+
let currStatus = this.lendingStatus;
|
|
241
|
+
if (action === 'browse_book') {
|
|
242
|
+
currStatus = {
|
|
243
|
+
...this.lendingStatus,
|
|
244
|
+
available_to_browse: false,
|
|
245
|
+
};
|
|
246
|
+
} else if (action === 'borrow_book') {
|
|
247
|
+
currStatus = {
|
|
248
|
+
...this.lendingStatus,
|
|
249
|
+
available_to_borrow: false,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
this.lendingStatus = currStatus;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* show error message if something went wrong */
|
|
257
|
+
async showErrorModal(errorMsg, action) {
|
|
258
|
+
this.disableActionGroup = false;
|
|
259
|
+
|
|
260
|
+
// check if this.modal passed as prop
|
|
261
|
+
if (!this.modal) {
|
|
262
|
+
this.modal = document.querySelector('modal-manager');
|
|
263
|
+
|
|
264
|
+
// check the DOM if <modal-manager> already there
|
|
265
|
+
if (!this.modal) this.modal = document.createElement('modal-manager');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this.modal.id = 'action-bar-modal';
|
|
269
|
+
await document.body.appendChild(this.modal);
|
|
270
|
+
|
|
271
|
+
const modalConfig = new ModalConfig({
|
|
272
|
+
title: 'Lending error',
|
|
273
|
+
message: errorMsg,
|
|
274
|
+
headerColor: '#d9534f',
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
if (action === 'create_token') {
|
|
278
|
+
modalConfig.closeOnBackdropClick = false;
|
|
279
|
+
modalConfig.showCloseButton = false;
|
|
280
|
+
modalConfig.message = html` Uh oh, something went wrong trying to access
|
|
281
|
+
this book.<br />
|
|
282
|
+
Please <a href="${() => window.location.reload(true)}">refresh</a> to
|
|
283
|
+
try again or send us an email to
|
|
284
|
+
<a
|
|
285
|
+
href="mailto:info@archive.org?subject=Help: cannot access my borrowed book: ${this
|
|
286
|
+
.identifier}"
|
|
287
|
+
>info@archive.org</a
|
|
288
|
+
>`;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
this.modal.showModal({
|
|
292
|
+
config: modalConfig,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
182
296
|
get iconClass() {
|
|
183
297
|
return this.width <= mobileContainerWidth ? 'mobile' : 'desktop';
|
|
184
298
|
}
|
|
@@ -23,10 +23,12 @@ const container = ({
|
|
|
23
23
|
text: 'Purchase',
|
|
24
24
|
},
|
|
25
25
|
],
|
|
26
|
+
borrowType = '',
|
|
26
27
|
} = {}) =>
|
|
27
28
|
html`<collapsible-action-group
|
|
28
29
|
.primaryActions=${primaryActions}
|
|
29
30
|
.secondaryActions=${secondaryActions}
|
|
31
|
+
.borrowType=${borrowType}
|
|
30
32
|
></collapsible-action-group>`;
|
|
31
33
|
|
|
32
34
|
describe('<collapsible-action-group>', () => {
|
|
@@ -39,6 +41,22 @@ describe('<collapsible-action-group>', () => {
|
|
|
39
41
|
const primaryButton = primaryActionContainer.querySelector('.ia-button');
|
|
40
42
|
expect(primaryButton.innerText).to.equal('Borrow for 1 hour');
|
|
41
43
|
});
|
|
44
|
+
|
|
45
|
+
it('check if loader is active and action-group is disabled', async () => {
|
|
46
|
+
const el = await fixture(container());
|
|
47
|
+
|
|
48
|
+
const primaryActionContainer = el.shadowRoot.querySelector('.primary');
|
|
49
|
+
primaryActionContainer
|
|
50
|
+
.querySelector('.ia-button')
|
|
51
|
+
.dispatchEvent(new CustomEvent('toggle-loader'));
|
|
52
|
+
el.disabled = true;
|
|
53
|
+
await el.updateComplete;
|
|
54
|
+
|
|
55
|
+
expect(el.disabled).to.be.true;
|
|
56
|
+
expect(el.shadowRoot.querySelector('div').classList.contains('disabled')).to
|
|
57
|
+
.be.true;
|
|
58
|
+
});
|
|
59
|
+
|
|
42
60
|
it('fires analytics events', async () => {
|
|
43
61
|
const el = await fixture(container());
|
|
44
62
|
const primaryActionContainer = el.shadowRoot.querySelector('.primary');
|
|
@@ -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({
|