@internetarchive/ia-book-actions 0.0.5 → 0.0.6-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.
@@ -0,0 +1,93 @@
1
+ import { html, css } from 'lit-element';
2
+
3
+ import {
4
+ analyticsCategories,
5
+ analyticsActions,
6
+ } from '../core/config/analytics-event-and-category.js';
7
+ import ActionsHandler from '../core/services/actions-handler/actions-handler.js';
8
+
9
+ import { archiveLogo } from '../assets/data/archive-logo.js';
10
+
11
+ export class BookTitleBar extends ActionsHandler {
12
+ static get properties() {
13
+ return {
14
+ identifier: { type: String },
15
+ bookTitle: { type: String },
16
+ };
17
+ }
18
+
19
+ constructor() {
20
+ super();
21
+ this.identifier = '';
22
+ this.bookTitle = '';
23
+ this.analyticsCategories = analyticsCategories;
24
+ this.analyticsActions = analyticsActions;
25
+ }
26
+
27
+ /**
28
+ * Click handler to emit custom event on action click
29
+ */
30
+ clickHandler() {
31
+ const { category, action } = {
32
+ category: this.analyticsCategories.bookReaderHeader,
33
+ action: this.analyticsActions.titleBar,
34
+ };
35
+
36
+ this.dispatchEvent(
37
+ new CustomEvent('bookTitleBar', {
38
+ detail: {
39
+ event: { category, action },
40
+ },
41
+ })
42
+ );
43
+ }
44
+
45
+ render() {
46
+ return html`
47
+ <a
48
+ class="embed-link"
49
+ @click=${() => {
50
+ this.clickHandler();
51
+ }}
52
+ href="/details/${this.identifier}"
53
+ >
54
+ <span>${archiveLogo}</span>
55
+ <span class="title">${this.bookTitle}</span>
56
+ </a>
57
+ `;
58
+ }
59
+
60
+ static get styles() {
61
+ return css`
62
+ :host {
63
+ padding: 0 10px;
64
+ height: 3.4rem;
65
+ display: flex;
66
+ }
67
+ .embed-link {
68
+ display: inline-flex;
69
+ align-items: center;
70
+ text-decoration: none;
71
+ color: var(--primaryTextColor, #fff);
72
+ font-size: 1.4rem;
73
+ }
74
+ .embed-link .title {
75
+ display: -webkit-box;
76
+ -webkit-box-orient: vertical;
77
+ -webkit-line-clamp: 2;
78
+ overflow: hidden;
79
+ text-align: left;
80
+ line-height: initial;
81
+ }
82
+ .embed-link svg {
83
+ margin-right: 0.5rem;
84
+ display: block;
85
+ }
86
+ .embed-link:hover {
87
+ text-decoration: underline;
88
+ }
89
+ `;
90
+ }
91
+ }
92
+
93
+ window.customElements.define('book-title-bar', BookTitleBar);
@@ -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,6 +44,7 @@ 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) {
@@ -94,13 +97,20 @@ export class CollapsibleActionGroup extends ActionsHandler {
94
97
 
95
98
  render() {
96
99
  return html`
97
- ${this.getLoaderIcon}
98
- <section class="action-buttons primary">
99
- ${this.renderPrimaryActions}
100
- </section>
101
- <section class="action-buttons secondary">
102
- ${this.renderSecondaryActions}
103
- </section>
100
+ <div
101
+ class="${classMap({
102
+ actiongroup: true,
103
+ disabled: this.disabled,
104
+ })}"
105
+ >
106
+ ${this.getLoaderIcon}
107
+ <section class="action-buttons primary">
108
+ ${this.renderPrimaryActions}
109
+ </section>
110
+ <section class="action-buttons secondary">
111
+ ${this.renderSecondaryActions}
112
+ </section>
113
+ </div>
104
114
  `;
105
115
  }
106
116
 
@@ -225,7 +235,14 @@ export class CollapsibleActionGroup extends ActionsHandler {
225
235
  * @returns { HTMLElement }
226
236
  */
227
237
  get getLoaderIcon() {
228
- return html`<img class="action-loader" alt="" src="${this.loaderIcon}" />`;
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
  /**
@@ -6,9 +6,8 @@ export const analyticsCategories = {
6
6
  browse: 'BookReader-ReadingBrowse',
7
7
  preview: 'BookReader-Preview',
8
8
  satisfactionMetric: 'DetailsPage-Book',
9
- purchase: 'BookReaderHeader',
10
- unavailable: 'BookReader-Preview',
11
- admin: 'Admin',
9
+ bookReaderHeader: 'BookReader-Header',
10
+ adminAccess: 'Admin-Access',
12
11
  };
13
12
 
14
13
  export const analyticsActions = {
@@ -21,4 +20,6 @@ export const analyticsActions = {
21
20
  login: 'LogIn',
22
21
  purchase: 'BWBPurchase',
23
22
  unavailable: 'Book-Unavailable',
23
+ printDisability: 'Print-Disability',
24
+ titleBar: 'Book-Title-Bar',
24
25
  };
@@ -33,7 +33,7 @@ export default class ActionsConfig {
33
33
  this.analyticsActions = analyticsActions;
34
34
  }
35
35
 
36
- browseBookConfig() {
36
+ firstBrowseConfig() {
37
37
  return {
38
38
  id: 'browseBook',
39
39
  text: 'Borrow for 1 hour',
@@ -45,10 +45,22 @@ export default class ActionsConfig {
45
45
  };
46
46
  }
47
47
 
48
+ browseAgainConfig() {
49
+ return {
50
+ id: 'browseBookAgain',
51
+ text: 'Borrow again',
52
+ className: 'primary',
53
+ analyticsEvent: {
54
+ category: this.analyticsCategories.browse,
55
+ action: this.analyticsActions.browseAgain,
56
+ },
57
+ };
58
+ }
59
+
48
60
  returnBookConfig() {
49
61
  const eventCategory = this.lendingStatus.user_has_browsed
50
- ? 'browse'
51
- : 'borrow';
62
+ ? this.analyticsCategories.browse
63
+ : this.analyticsCategories.borrow;
52
64
 
53
65
  return {
54
66
  id: 'returnNow',
@@ -77,7 +89,7 @@ export default class ActionsConfig {
77
89
  analyticsEvent: {
78
90
  category: this.lendingStatus.user_has_browsed
79
91
  ? this.analyticsCategories.browse
80
- : this.analyticsCategories.borrow,
92
+ : this.analyticsCategories.preview,
81
93
  action: this.analyticsActions.borrow,
82
94
  },
83
95
  };
@@ -161,7 +173,7 @@ export default class ActionsConfig {
161
173
  target: '_blank',
162
174
  className: 'purchase dark',
163
175
  analyticsEvent: {
164
- category: this.analyticsCategories.purchase,
176
+ category: this.analyticsCategories.bookReaderHeader,
165
177
  action: this.analyticsActions.purchase,
166
178
  },
167
179
  };
@@ -179,8 +191,8 @@ export default class ActionsConfig {
179
191
  target: '_self',
180
192
  className: 'print-disability',
181
193
  analyticsEvent: {
182
- category: this.analyticsCategories.purchase,
183
- action: this.analyticsActions.purchase,
194
+ category: this.analyticsCategories.bookReaderHeader,
195
+ action: this.analyticsActions.printDisability,
184
196
  },
185
197
  };
186
198
  }
@@ -198,7 +210,7 @@ export default class ActionsConfig {
198
210
  target: '_self',
199
211
  className: 'danger',
200
212
  analyticsEvent: {
201
- category: this.analyticsCategories.admin,
213
+ category: this.analyticsCategories.adminAccess,
202
214
  action: this.analyticsActions.borrow,
203
215
  },
204
216
  };
@@ -216,7 +228,7 @@ export default class ActionsConfig {
216
228
  target: '_self',
217
229
  className: 'ia-button',
218
230
  analyticsEvent: {
219
- category: this.analyticsCategories.admin,
231
+ category: this.analyticsCategories.adminAccess,
220
232
  action: this.analyticsActions.doneBorrowing,
221
233
  },
222
234
  };
@@ -229,7 +241,7 @@ export default class ActionsConfig {
229
241
  className: 'primary unavailable',
230
242
  disabled: true,
231
243
  analyticsEvent: {
232
- category: this.analyticsCategories.unavailable,
244
+ category: this.analyticsCategories.preview,
233
245
  action: this.analyticsActions.unavailable,
234
246
  },
235
247
  };
@@ -10,19 +10,15 @@ export default function ActionsHandlerService(options) {
10
10
  identifier: '',
11
11
  data: {},
12
12
  success() {},
13
- error: null,
13
+ error() {},
14
14
  loader: true,
15
15
  type: 'POST',
16
16
  ...options,
17
17
  };
18
18
 
19
- if (option.loader) {
20
- showActionButtonLoader();
21
- }
22
-
23
19
  let baseHost = '';
24
20
  if (window.location.pathname === '/demo/') {
25
- baseHost = `/demo/`;
21
+ baseHost = `/demo/1`;
26
22
  } else {
27
23
  baseHost = `/services/loans/loan`;
28
24
  }
@@ -36,23 +32,21 @@ export default function ActionsHandlerService(options) {
36
32
  body: formData,
37
33
  })
38
34
  .then(response => {
39
- if (response.status === 200) {
40
- option.success.call();
35
+ if (baseHost == '/demo/1' || baseHost == '/demo/') {
36
+ return {"error":"Unexpected error.\nPlease email this link to openlibrary@archive.org with the subject: Unexpected error. Thank you. \nMessage:UNAVAILABLE"};
41
37
  }
38
+
39
+ // The response is a Response instance.
40
+ // You parse the data into a useable format using `.json()`
41
+ return response.json();
42
42
  })
43
- .catch(error => {
44
- console.log(error);
43
+ .then(data => {
44
+ // `data` is the parsed version of the JSON returned from the above endpoint.
45
+ console.log('actual reponse for endpoint', data);
46
+ if (!data.error) {
47
+ option?.success(data);
48
+ } else {
49
+ option?.error(data);
50
+ }
45
51
  });
46
52
  }
47
-
48
- function showActionButtonLoader() {
49
- const collapsibleElement = document
50
- .querySelector('ia-book-actions')
51
- .shadowRoot.querySelector('collapsible-action-group');
52
- collapsibleElement.setAttribute('style', 'opacity:0.8; pointer-events:none');
53
-
54
- const actionLoader = collapsibleElement.shadowRoot.querySelector(
55
- '.action-loader'
56
- );
57
- actionLoader.setAttribute('style', 'visibility: visible');
58
- }
@@ -7,17 +7,14 @@ 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. action: action name like browse_book, return_book, borrow_book etc...
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 = 5000;
17
+ this.ajaxTimeout = 6000;
21
18
  this.bindEvents();
22
19
  }
23
20
 
@@ -82,56 +79,101 @@ export default class ActionsHandler extends LitElement {
82
79
  const { category, action } = detail.event;
83
80
  this.sendEvent(category, action);
84
81
  });
82
+
83
+ this.addEventListener('bookTitleBar', ({ detail }) => {
84
+ const { category, action } = detail.event;
85
+ this.sendEvent(category, action);
86
+ });
85
87
  }
86
88
 
87
89
  handleBrowseIt() {
90
+ const context = 'browse_book';
91
+ this.toggleActionBarState(context);
92
+
88
93
  ActionsHandlerService({
89
- action: 'browse_book',
94
+ action: context,
90
95
  identifier: this.identifier,
91
96
  success: () => {
92
97
  this.handleReadItNow();
93
98
  },
99
+ error: data => {
100
+ console.log(data);
101
+ alert(data.error);
102
+ this.toggleActionBarState(context, data);
103
+ },
94
104
  });
95
105
  }
96
106
 
97
107
  handleReturnIt() {
108
+ const context = 'return_loan';
109
+ this.toggleActionBarState(context);
110
+
98
111
  ActionsHandlerService({
99
- action: 'return_loan',
112
+ action: context,
100
113
  identifier: this.identifier,
101
114
  success: () => {
102
115
  this.deleteLoanCookies();
103
116
  URLHelper.goToUrl(`/details/${this.identifier}`, true);
104
117
  },
118
+ error: data => {
119
+ console.log(data);
120
+ alert(data.error);
121
+ this.toggleActionBarState(context);
122
+ },
105
123
  });
106
124
  }
107
125
 
108
126
  handleBorrowIt() {
127
+ const context = 'borrow_book';
128
+ this.toggleActionBarState(context);
129
+
109
130
  ActionsHandlerService({
110
- action: 'borrow_book',
131
+ action: context,
111
132
  identifier: this.identifier,
112
133
  success: () => {
113
134
  this.handleReadItNow();
114
135
  },
136
+ error: data => {
137
+ console.log(data);
138
+ alert(data.error);
139
+ this.toggleActionBarState(context, data);
140
+ },
115
141
  });
116
142
  }
117
143
 
118
144
  handleReserveIt() {
145
+ const context = 'join_waitlist';
146
+ this.toggleActionBarState(context);
147
+
119
148
  ActionsHandlerService({
120
- action: 'join_waitlist',
149
+ action: context,
121
150
  identifier: this.identifier,
122
151
  success: () => {
123
152
  URLHelper.goToUrl(URLHelper.getRedirectUrl(), true);
124
153
  },
154
+ error: data => {
155
+ console.log(data);
156
+ alert(data.error);
157
+ this.toggleActionBarState(context);
158
+ },
125
159
  });
126
160
  }
127
161
 
128
162
  handleRemoveFromWaitingList() {
163
+ const context = 'leave_waitlist';
164
+ this.toggleActionBarState(context);
165
+
129
166
  ActionsHandlerService({
130
- action: 'leave_waitlist',
167
+ action: context,
131
168
  identifier: this.identifier,
132
169
  success: () => {
133
170
  URLHelper.goToUrl(URLHelper.getRedirectUrl(), true);
134
171
  },
172
+ error: data => {
173
+ console.log(data);
174
+ alert(data.error);
175
+ this.toggleActionBarState(context);
176
+ },
135
177
  });
136
178
  }
137
179
 
@@ -184,4 +226,12 @@ export default class ActionsHandler extends LitElement {
184
226
  cookie += '; path=/; domain=.archive.org;';
185
227
  document.cookie = cookie;
186
228
  }
229
+
230
+ toggleActionBarState(context, data = {}) {
231
+ this.dispatchEvent(
232
+ new CustomEvent('toggle-action-bar-state', {
233
+ detail: { context, data }
234
+ })
235
+ );
236
+ }
187
237
  }
@@ -2,7 +2,6 @@
2
2
  /* eslint no-console: "off" */
3
3
  /* eslint no-nested-ternary: "off" */
4
4
  /* eslint-disable */
5
- import { nothing } from 'lit-html';
6
5
  import { URLHelper } from '../config/url-helper.js';
7
6
  import {
8
7
  analyticsCategories,
@@ -104,7 +103,7 @@ export default class GetLendingActions {
104
103
  const leaveWaitlist = this.actionsConfig.leaveWaitlistConfig();
105
104
  const borrowBook = this.actionsConfig.borrowBookConfig();
106
105
  const browseBook = lendingStatus.available_to_browse
107
- ? this.actionsConfig.browseBookConfig()
106
+ ? this.actionsConfig.firstBrowseConfig()
108
107
  : null;
109
108
 
110
109
  const dropdownOptions = browseBook ? [browseBook, borrowBook] : [];
@@ -150,7 +149,7 @@ export default class GetLendingActions {
150
149
  primaryTitle: 'You are on the waitlist for this book.',
151
150
  primaryActions: [
152
151
  this.actionsConfig.leaveWaitlistConfig(),
153
- this.actionsConfig.browseBookConfig(),
152
+ this.actionsConfig.firstBrowseConfig(),
154
153
  ],
155
154
  primaryColor: 'primary',
156
155
  secondaryActions: [
@@ -160,10 +159,18 @@ export default class GetLendingActions {
160
159
  };
161
160
  }
162
161
 
162
+ // check restricted item behaviour here /activemeasuresse0000ridt
163
163
  restrictedAction() {
164
- // check restricted item behaviour here /activemeasuresse0000ridt
164
+ const lendingStatus = this.lendingStatus || {};
165
+ const anotherPatronUsing =
166
+ lendingStatus.max_browsable_copies &&
167
+ !lendingStatus.available_lendable_copies;
168
+ const title = anotherPatronUsing
169
+ ? 'Another patron is using this book. Please check back later.'
170
+ : 'This book is not available at this time.';
171
+
165
172
  return {
166
- primaryTitle: 'This book is not available at this time.',
173
+ primaryTitle: title,
167
174
  primaryActions: [this.actionsConfig.unavailableBookConfig()],
168
175
  primaryColor: 'primary',
169
176
  secondaryActions: [
@@ -192,7 +199,9 @@ export default class GetLendingActions {
192
199
  borrow = this.actionsConfig.unavailableBookConfig();
193
200
  }
194
201
 
195
- const actions = [borrow, waitlist].filter(action => {
202
+ const printDisability = this.actionsConfig.printDisabilityConfig();
203
+
204
+ const actions = [borrow, waitlist, printDisability].filter(action => {
196
205
  return action !== null;
197
206
  });
198
207
 
@@ -255,25 +264,9 @@ export default class GetLendingActions {
255
264
  : possibleTitles.one_hour;
256
265
 
257
266
  // one hour borrow config
258
- const oneHrBorrowText = browsingHasExpired
259
- ? 'Borrow again'
260
- : 'Borrow for 1 hour';
261
- const browseAgainEvent = {
262
- category: this.analyticsCategories.browse,
263
- action: this.analyticsActions.browseAgain,
264
- };
265
- const firstBrowseEvent = {
266
- category: this.analyticsCategories.preview,
267
- action: this.analyticsActions.browse,
268
- };
269
- const oneHrBorrowEvent = browsingHasExpired
270
- ? browseAgainEvent
271
- : firstBrowseEvent;
272
-
273
- const oneHrBorrow = this.actionsConfig.browseBookConfig(
274
- oneHrBorrowText,
275
- oneHrBorrowEvent
276
- );
267
+ const oneHrBorrow = browsingHasExpired
268
+ ? this.actionsConfig.browseAgainConfig()
269
+ : this.actionsConfig.firstBrowseConfig();
277
270
 
278
271
  const borrow = this.actionsConfig.borrowBookConfig();
279
272
  const waitlist = this.actionsConfig.waitlistConfig();
@@ -308,10 +301,7 @@ export default class GetLendingActions {
308
301
  return this.loggedOutOptions();
309
302
  }
310
303
 
311
- const canBrowse =
312
- lendingStatus.available_to_browse ||
313
- (!lendingStatus.available_to_browse && lendingStatus.browsingExpired);
314
- if (canBrowse) {
304
+ if (lendingStatus.available_to_browse || lendingStatus.browsingExpired) {
315
305
  return this.borrow1HrAction();
316
306
  }
317
307
 
@@ -378,7 +368,8 @@ export default class GetLendingActions {
378
368
  lendingStatus.user_is_printdisabled;
379
369
 
380
370
  const patronIsReading =
381
- lendingStatus.user_has_borrowed || lendingStatus.user_has_browsed;
371
+ lendingStatus.user_has_borrowed ||
372
+ (lendingStatus.user_has_browsed && !lendingStatus.browsingExpired);
382
373
 
383
374
  const notBorrowed =
384
375
  !lendingStatus.user_has_borrowed && !lendingStatus.user_has_browsed;
@@ -414,7 +405,7 @@ export default class GetLendingActions {
414
405
  lendingActions = this.leaveWaitlistAction();
415
406
  } else if (userCanAccessPrintDisabled) {
416
407
  lendingActions = this.borrowPrintDisabledAction();
417
- } else if (canBorrow) {
408
+ } else if (canBorrow || lendingStatus.browsingExpired) {
418
409
  lendingActions = this.borrowAction();
419
410
  } else if (lendingStatus.isPrintDisabledOnly) {
420
411
  lendingActions = this.onlyPrintDisabledAction();