@internetarchive/ia-book-actions 0.0.19-5 → 0.0.21

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/demo/index.html CHANGED
@@ -101,6 +101,9 @@
101
101
 
102
102
  let iaBookActions = document.querySelector('ia-book-actions');
103
103
 
104
+ // for debugging
105
+ window.iaBookActions = iaBookActions;
106
+
104
107
  const modalConfig = new ModalConfig();
105
108
  modalConfig.headerColor = '#d9534f';
106
109
 
@@ -214,6 +217,12 @@
214
217
  lendingStatus1.user_on_waitlist = false;
215
218
  lendingStatus1.available_to_waitlist = false;
216
219
  lendingStatus1.user_has_borrowed = false;
220
+ } else if (e.target.value === 'user_can_claim_waitlist') {
221
+ lendingStatus1.available_to_borrow = true;
222
+ lendingStatus1.user_on_waitlist = true;
223
+ lendingStatus1.user_can_claim_waitlist = true;
224
+ lendingStatus1.user_has_borrowed = false;
225
+ lendingStatus1.available_to_waitlist = false;
217
226
  } else if (e.target.value === 'user_on_waitlist') {
218
227
  lendingStatus1.available_to_borrow = false;
219
228
  lendingStatus1.user_on_waitlist = true;
@@ -283,6 +292,7 @@
283
292
  <td class="availableToBorrow">
284
293
  <label><input type="radio" name="borrow" value="available_to_borrow" />available_to_borrow</label>
285
294
  <label><input type="radio" name="borrow" value="user_on_waitlist" />user_on_waitlist</label>
295
+ <label><input type="radio" name="borrow" value="user_can_claim_waitlist" />user_can_claim_waitlist</label>
286
296
  <label><input type="radio" name="borrow" value="available_to_waitlist" />available_to_waitlist</label>
287
297
  <label><input type="radio" name="borrow" value="user_has_borrowed" />user_has_borrowed</label>
288
298
  </td>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/ia-book-actions",
3
- "version": "0.0.19-5",
3
+ "version": "0.0.21",
4
4
  "description": "Bookreader actions for borrowable book",
5
5
  "author": "Internet Archive",
6
6
  "license": "AGPL-3.0-only",
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "@internetarchive/icon-info": "^1.2.6",
22
22
  "@internetarchive/local-cache": "^0.2.0",
23
- "@internetarchive/modal-manager": "^0.1.0",
23
+ "@internetarchive/modal-manager": "^0.2.1",
24
24
  "@internetarchive/shared-resize-observer": "^0.2.0",
25
25
  "lit": "^2.2.1"
26
26
  },
@@ -40,7 +40,7 @@
40
40
  "husky": "^1.0.0",
41
41
  "lint-staged": "^10.0.0",
42
42
  "prettier": "^2.0.4",
43
- "sinon": "^9.2.4"
43
+ "sinon": "^13.0.2"
44
44
  },
45
45
  "eslintConfig": {
46
46
  "extends": [
@@ -14,15 +14,18 @@ export default css`
14
14
  align-items: center;
15
15
  }
16
16
  .action-buttons .ia-button {
17
- margin: 0;
17
+ display: inline-flex;
18
+ align-items: center;
19
+ vertical-align: middle;
18
20
  height: 3.5rem;
21
+ transition: all 0.1s ease 0s;
22
+ vertical-align: middle;
23
+ padding: 0 1rem;
24
+ margin: 0 3px;
19
25
  }
20
26
  .primary,
21
27
  .secondary {
22
28
  position: relative;
23
- background-color: var(--white, #fff);
24
- border-radius: 5px;
25
- margin: 0 3px;
26
29
  }
27
30
  .primary .initial {
28
31
  border-radius: 0.4rem 0 0 0.4rem;
@@ -48,9 +51,9 @@ export default css`
48
51
  }
49
52
  .dropdown-content .ia-button {
50
53
  background: none;
51
- color: var(--primaryTextColor, #fff);
52
54
  border: none;
53
55
  box-sizing: border-box;
56
+ display: block;
54
57
  width: 100%;
55
58
  text-align: left;
56
59
  height: 3rem;
@@ -58,9 +61,6 @@ export default css`
58
61
  padding: 0.6rem 1.2rem;
59
62
  margin: 0;
60
63
  }
61
- .dropdown-content .ia-button:is(:focus-visible, :hover) {
62
- background: unset;
63
- }
64
64
  .dropdown-content li .ia-button {
65
65
  border-radius: 0;
66
66
  }
@@ -115,9 +115,6 @@ export default css`
115
115
  display: inline-block;
116
116
  vertical-align: middle;
117
117
  }
118
- .secondary .ia-button.exit-admin {
119
- background-color: var(--primaryBGColor);
120
- }
121
118
  .purchase small {
122
119
  display: block;
123
120
  font-size: 1rem;
@@ -3,88 +3,63 @@ import { css } from 'lit';
3
3
  export default css`
4
4
  .ia-button {
5
5
  min-height: 3rem;
6
+ border: none;
7
+ outline: none;
6
8
  cursor: pointer;
7
- color: var(--primaryTextColor, #fff);
9
+ color: #fff;
8
10
  line-height: normal;
9
11
  border-radius: 0.4rem;
12
+ text-align: center;
13
+ vertical-align: middle;
10
14
  font-size: 1.4rem;
11
15
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
16
+ display: inline-block;
17
+ padding: 0.85rem 1.2rem;
12
18
  border: 1px solid transparent;
13
19
  white-space: nowrap;
14
20
  appearance: auto;
15
21
  box-sizing: border-box;
16
- display: flex;
17
- align-items: center;
18
- transition: all 0.1s ease 0s;
19
- vertical-align: middle;
20
- padding: 0 1rem;
21
- outline-color: var(--primaryTextColor, #fff);
22
- outline-offset: -4px;
23
- user-select: none;
24
- text-decoration: none;
25
- width: fit-content;
26
22
  -webkit-user-select: none;
27
23
  -moz-user-select: none;
28
24
  -ms-user-select: none;
29
25
  -o-user-select: none;
26
+ user-select: none;
30
27
  }
31
- .ia-button:is(:focus-visible) {
32
- outline-style: double;
33
- }
34
-
35
- .ia-button:disabled {
28
+ .ia-button:disabled,
29
+ .ia-button.disabled {
36
30
  cursor: not-allowed;
37
31
  background-color: var(--primaryDisableCTAFill, #767676);
38
32
  border: 1px solid var(--secondaryCTABorder, #999);
33
+ color: var(--primaryTextColor, #fff);
39
34
  }
40
35
  .ia-button.transparent {
41
36
  background-color: transparent;
42
37
  }
43
38
 
44
- .ia-button.warning {
45
- background-color: #ee8950;
46
- border-color: #ec7939;
39
+ .ia-button.slim {
40
+ padding: 0;
47
41
  }
48
-
49
42
  .ia-button.primary {
50
- background-color: var(--primaryCTAFill, #194880);
43
+ background-color: #194880;
51
44
  border-color: #c5d1df;
52
45
  }
53
- .ia-button.primary:is(:hover) {
54
- background-color: rgba(27, 72, 128, 0.9);
55
- }
56
- .ia-button.primary:is(:focus-visible) {
57
- background-color: rgba(27, 72, 128, 0.8);
58
- }
59
- .ia-button.primary:is(:active) {
60
- background-color: rgba(27, 72, 128, 0.7);
61
- }
62
-
63
- .ia-button.danger {
64
- background-color: var(--primaryErrorCTAFill, #e51c26);
65
- border-color: #d43f3a;
66
- }
67
- .ia-button.danger:is(:hover) {
68
- background-color: rgba(229, 28, 38, 0.9);
69
- }
70
- .ia-button.danger:is(:focus-visible) {
71
- background-color: rgba(229, 28, 38, 0.8);
72
- }
73
- .ia-button.danger:is(:active) {
74
- background-color: rgba(229, 28, 38, 0.7);
75
- }
76
-
77
46
  .ia-button.dark {
78
- background-color: var(--secondaryCTAFill, #333);
47
+ color: #fff;
48
+ background-color: #333;
79
49
  border-color: #979797;
80
50
  }
81
- .ia-button.dark:is(:hover) {
82
- background-color: rgba(51, 51, 51, 0.9);
51
+ .ia-button.danger {
52
+ color: #fff;
53
+ background-color: #d9534f;
54
+ border-color: #d43f3a;
83
55
  }
84
- .ia-button.dark:is(:focus-visible) {
85
- background-color: rgba(51, 51, 51, 0.8);
56
+ .ia-button.warning {
57
+ color: #fff;
58
+ background-color: #ee8950;
59
+ border-color: #ec7939;
86
60
  }
87
- .ia-button.dark:is(:active) {
88
- background-color: rgba(51, 51, 51, 0.7);
61
+ .ia-button.cancel {
62
+ background-color: #e51c26;
63
+ border-color: #f8c6c8;
89
64
  }
90
65
  `;
@@ -50,10 +50,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
50
50
  }
51
51
 
52
52
  updated(changed) {
53
- if (
54
- (changed.has('width') || changed.has('disabled')) &&
55
- this.isBelowTabletContainer
56
- ) {
53
+ if (changed.has('width') && this.isBelowTabletContainer) {
57
54
  this.resetActions();
58
55
  }
59
56
  }
@@ -113,9 +110,6 @@ export class CollapsibleActionGroup extends ActionsHandler {
113
110
  <section class="action-buttons secondary">
114
111
  ${this.renderSecondaryActions}
115
112
  </section>
116
- <section class="action-buttons secondary purchase">
117
- ${this.renderPurchaseAction}
118
- </section>
119
113
  </div>
120
114
  `;
121
115
  }
@@ -153,27 +147,13 @@ export class CollapsibleActionGroup extends ActionsHandler {
153
147
  return this.secondaryActions.map(action => this.renderActionLink(action));
154
148
  }
155
149
 
156
- get renderPurchaseAction() {
157
- if (!this.secondaryActions.length) return nothing;
158
-
159
- if (this.secondaryActions.length === 2) {
160
- return this.renderActionLink(this.secondaryActions[1], true);
161
- }
162
- if (this.secondaryActions[0].id === 'purchaseBook') {
163
- return this.renderActionLink(this.secondaryActions[0], true);
164
- }
165
- return nothing;
166
- }
167
-
168
150
  /**
169
- * Render action as a link for secondary actions like admin, printdisability links.
151
+ * Render action as a link for secondary actions like admin, purchase, printdisability links.
170
152
  * @param { Object } action
171
153
  * @param { Boolean } initialButton
172
154
  * @returns { HTMLElement }
173
155
  */
174
156
  renderActionLink(action, initialButton = false) {
175
- if (!initialButton && action?.id === 'purchaseBook') return nothing; // handle purchase action differerntly
176
-
177
157
  return html`<a
178
158
  class="ia-button ${action.className} ${initialButton ? 'initial' : ''}"
179
159
  href="${action.url}"
@@ -226,7 +226,7 @@ export default class ActionsConfig {
226
226
  text: message,
227
227
  url: URLHelper.getBackHref(),
228
228
  target: '_self',
229
- className: 'exit-admin',
229
+ className: 'ia-button',
230
230
  analyticsEvent: {
231
231
  category: this.analyticsCategories.adminAccess,
232
232
  action: this.analyticsActions.doneBorrowing,
@@ -22,6 +22,8 @@ export default class ActionsHandler extends LitElement {
22
22
  }
23
23
 
24
24
  sendEvent(eventCategory, eventAction) {
25
+ // eslint-disable-next-line no-console
26
+ console?.log('Book action: ', { eventCategory, eventAction });
25
27
  window?.archive_analytics?.send_event_no_sampling(
26
28
  eventCategory,
27
29
  eventAction,
@@ -34,7 +34,26 @@ import ActionsConfig from './actions-config.js';
34
34
  * The action buttons configuration is coming from ActionsConfig class.
35
35
  */
36
36
 
37
- export default class GetLendingActions {
37
+ /**
38
+ * Enum: Book Titles
39
+ * @readonly
40
+ * @enum {string}
41
+ */
42
+ export const bookTitles = {
43
+ available_1hr: 'Renewable every hour, pending availability.',
44
+ available_14d: 'This book can be borrowed for 14 days.',
45
+ available_pd: 'Book available to patrons with print disabilities.',
46
+ available_waitlist: 'A waitlist is available.',
47
+ admin_access: 'You have administrative privileges to read this book.',
48
+ claim_waitlist: 'You are at the top of the waitlist for this book.',
49
+ being_borrowed: 'Another patron is using this book. Please check back later.',
50
+ eligible_pd: 'You are eligible for print-disabled access.',
51
+ on_waitlist: 'You are on the waitlist for this book.',
52
+ session_expired: 'Your loan has expired.',
53
+ unavailable: 'This book is not available at this time.',
54
+ };
55
+
56
+ export class GetLendingActions {
38
57
  constructor(userid, identifier, lendingStatus, bwbPurchaseUrl) {
39
58
  this.userid = userid;
40
59
  this.identifier = identifier;
@@ -52,7 +71,7 @@ export default class GetLendingActions {
52
71
 
53
72
  onlyAdminAction() {
54
73
  return {
55
- primaryTitle: 'You have administrative privileges to read this book.',
74
+ primaryTitle: bookTitles.admin_access,
56
75
  primaryActions: [],
57
76
  primaryColor: 'primary',
58
77
  secondaryActions: [
@@ -100,7 +119,7 @@ export default class GetLendingActions {
100
119
  };
101
120
  }
102
121
 
103
- leaveWaitlistAction() {
122
+ claimWaitlistAction() {
104
123
  const lendingStatus = this.lendingStatus || {};
105
124
 
106
125
  const leaveWaitlist = this.actionsConfig.leaveWaitlistConfig();
@@ -109,12 +128,13 @@ export default class GetLendingActions {
109
128
  ? this.actionsConfig.firstBrowseConfig()
110
129
  : null;
111
130
 
112
- const dropdownOptions = browseBook ? [browseBook, borrowBook] : [];
113
- const actions = !browseBook ? [borrowBook, leaveWaitlist] : [leaveWaitlist];
131
+ let actions = [borrowBook];
132
+ if (browseBook) actions.push(browseBook);
133
+ actions.push(leaveWaitlist);
114
134
 
115
135
  return {
116
- primaryTitle: 'You are at the top of the waitlist for this book',
117
- primaryActions: actions.concat(dropdownOptions),
136
+ primaryTitle: bookTitles.claim_waitlist,
137
+ primaryActions: actions,
118
138
  primaryColor: 'primary',
119
139
  footer: 'printDisabilityLine()',
120
140
  secondaryActions: [
@@ -126,7 +146,7 @@ export default class GetLendingActions {
126
146
 
127
147
  borrowPrintDisabledAction() {
128
148
  return {
129
- primaryTitle: 'You are eligible for print-disabled access.',
149
+ primaryTitle: bookTitles.eligible_pd,
130
150
  primaryActions: [this.actionsConfig.borrowBookConfig()],
131
151
  primaryColor: 'primary',
132
152
  secondaryActions: [
@@ -141,7 +161,7 @@ export default class GetLendingActions {
141
161
  ? this.actionsConfig.unavailableBookConfig()
142
162
  : [];
143
163
  return {
144
- primaryTitle: 'Book available to patrons with print disabilities.',
164
+ primaryTitle: bookTitles.available_pd,
145
165
  primaryActions: [unavailable],
146
166
  primaryColor: 'primary',
147
167
  secondaryActions: [],
@@ -150,7 +170,7 @@ export default class GetLendingActions {
150
170
 
151
171
  onWaitlistAction() {
152
172
  return {
153
- primaryTitle: 'You are on the waitlist for this book.',
173
+ primaryTitle: bookTitles.on_waitlist,
154
174
  primaryActions: [
155
175
  this.actionsConfig.leaveWaitlistConfig(),
156
176
  this.actionsConfig.firstBrowseConfig(),
@@ -170,8 +190,8 @@ export default class GetLendingActions {
170
190
  lendingStatus.max_browsable_copies &&
171
191
  !lendingStatus.available_lendable_copies;
172
192
  const title = anotherPatronUsing
173
- ? 'Another patron is using this book. Please check back later.'
174
- : 'This book is not available at this time.';
193
+ ? bookTitles.being_borrowed
194
+ : bookTitles.unavailable;
175
195
 
176
196
  return {
177
197
  primaryTitle: title,
@@ -210,10 +230,10 @@ export default class GetLendingActions {
210
230
  });
211
231
 
212
232
  const title = lendingStatus.available_to_browse
213
- ? 'Renewable every hour, pending availability.'
233
+ ? bookTitles.available_1hr
214
234
  : lendingStatus.available_to_borrow
215
- ? 'This book can be borrowed for 14 days.'
216
- : 'Another patron is using this book.';
235
+ ? bookTitles.available_14d
236
+ : bookTitles.unavailable;
217
237
 
218
238
  return {
219
239
  primaryTitle: title,
@@ -260,12 +280,12 @@ export default class GetLendingActions {
260
280
  // end config
261
281
 
262
282
  const title = browsingHasExpired
263
- ? possibleTitles.session_expired
283
+ ? bookTitles.session_expired
264
284
  : !canBrowse && allBrowsableCopiesTaken
265
- ? possibleTitles.session_tryagain
285
+ ? bookTitles.being_borrowed
266
286
  : !canBrowse && lendingStatus.available_to_waitlist
267
- ? possibleTitles.waitlist
268
- : possibleTitles.one_hour;
287
+ ? bookTitles.available_waitlist
288
+ : bookTitles.available_1hr;
269
289
 
270
290
  // one hour borrow config
271
291
  const oneHrBorrow = browsingHasExpired
@@ -332,7 +352,7 @@ export default class GetLendingActions {
332
352
  });
333
353
 
334
354
  return {
335
- primaryTitle: waitlist ? 'Another patron is using this book.' : '',
355
+ primaryTitle: waitlist ? bookTitles.being_borrowed : '',
336
356
  primaryActions: actions,
337
357
  primaryColor: 'primary',
338
358
  secondaryActions: [
@@ -406,7 +426,7 @@ export default class GetLendingActions {
406
426
  } else if (patronIsReading) {
407
427
  lendingActions = this.patronIsReadingAction();
408
428
  } else if (lendingStatus.user_can_claim_waitlist) {
409
- lendingActions = this.leaveWaitlistAction();
429
+ lendingActions = this.claimWaitlistAction();
410
430
  } else if (userCanAccessPrintDisabled) {
411
431
  lendingActions = this.borrowPrintDisabledAction();
412
432
  } else if (canBorrow || lendingStatus.browsingExpired) {
@@ -419,6 +439,8 @@ export default class GetLendingActions {
419
439
  lendingActions = this.restrictedAction();
420
440
  }
421
441
 
442
+ // debugging console
443
+ console.log(lendingActions.primaryTitle);
422
444
  return lendingActions;
423
445
  }
424
446
  }
@@ -60,6 +60,8 @@ export class LoanTokenPoller {
60
60
  }
61
61
 
62
62
  sendEvent(eventCategory, eventAction) {
63
+ // eslint-disable-next-line no-console
64
+ console?.log('Book action: ', { eventCategory, eventAction });
63
65
  window?.archive_analytics?.send_event_no_sampling(
64
66
  eventCategory,
65
67
  eventAction,
@@ -75,8 +77,6 @@ export class LoanTokenPoller {
75
77
  error: data => {
76
78
  this.disconnectedInterval(); // stop token fetch api
77
79
  this.errorCallback({ detail: { action, data } });
78
- // send LendingServiceError to GA
79
- this.sendEvent('LendingServiceLoanError', action);
80
80
  },
81
81
  success: () => {
82
82
  if (isInitial) this.successCallback();
@@ -9,7 +9,7 @@ import './components/book-title-bar.js';
9
9
  import './components/text-group.js';
10
10
  import './components/info-icon.js';
11
11
 
12
- import GetLendingActions from './core/services/get-lending-actions.js';
12
+ import { GetLendingActions } from './core/services/get-lending-actions.js';
13
13
  import { mobileContainerWidth } from './core/config/constants.js';
14
14
  import { LoanTokenPoller } from './core/services/loan-token-poller.js';
15
15
 
@@ -1,5 +1,13 @@
1
1
  import { expect } from '@open-wc/testing';
2
- import GetLendingActions from '../../../src/core/services/get-lending-actions.js';
2
+ import sinon from 'sinon';
3
+ import {
4
+ GetLendingActions,
5
+ bookTitles,
6
+ } from '../../../src/core/services/get-lending-actions.js';
7
+
8
+ afterEach(() => {
9
+ sinon.restore();
10
+ });
3
11
 
4
12
  describe('Get Lending Actions', () => {
5
13
  it('Browsable and Borrowable with purchase link', async () => {
@@ -15,9 +23,7 @@ describe('Get Lending Actions', () => {
15
23
  );
16
24
  const actions = lendingOptions.getCurrentLendingActions();
17
25
 
18
- expect(actions.primaryTitle).to.equal(
19
- 'Renewable every hour, pending availability.'
20
- );
26
+ expect(actions.primaryTitle).to.equal(bookTitles.available_1hr);
21
27
  expect(actions.primaryActions.length).to.equal(3);
22
28
  expect(actions.primaryActions[0].text).to.equal('Borrow for 1 hour');
23
29
  expect(actions.primaryActions[1].text).to.equal('Borrow for 14 days');
@@ -37,9 +43,7 @@ describe('Get Lending Actions', () => {
37
43
  const actions = lendingOptions.getCurrentLendingActions();
38
44
 
39
45
  expect(actions.primaryActions.length).to.equal(2);
40
- expect(actions.primaryTitle).to.equal(
41
- 'This book can be borrowed for 14 days.'
42
- );
46
+ expect(actions.primaryTitle).to.equal(bookTitles.available_14d);
43
47
  expect(actions.primaryActions[0].text).to.equal('Log In and Borrow');
44
48
  });
45
49
 
@@ -64,24 +68,104 @@ describe('Get Lending Actions', () => {
64
68
  expect(actions.primaryActions[0].text).to.equal('Return now');
65
69
  });
66
70
 
67
- it('Reedem borrow action', async () => {
68
- const lendingOptions = new GetLendingActions(
69
- '@user',
70
- 'identifier',
71
- {
72
- is_lendable: true,
73
- available_to_borrow: true,
74
- user_can_claim_waitlist: true,
75
- },
76
- ''
77
- );
78
- const actions = lendingOptions.getCurrentLendingActions();
79
-
80
- expect(actions.primaryTitle).to.equal(
81
- 'You are at the top of the waitlist for this book'
82
- );
83
- expect(actions.primaryActions.length).to.equal(2);
84
- expect(actions.primaryActions[0].text).to.equal('Borrow for 14 days');
71
+ describe('WAITLIST', () => {
72
+ describe('`user_can_claim_waitlist = true`', () => {
73
+ it('top of waitlist & cannot browse', async () => {
74
+ const lendingOptions = new GetLendingActions(
75
+ '@user',
76
+ 'identifier',
77
+ {
78
+ is_lendable: true,
79
+ available_to_borrow: true,
80
+ user_can_claim_waitlist: true,
81
+ },
82
+ ''
83
+ );
84
+
85
+ const spy = sinon.spy(lendingOptions, 'claimWaitlistAction');
86
+ const actions = lendingOptions.getCurrentLendingActions();
87
+
88
+ expect(actions.primaryTitle).to.equal(bookTitles.claim_waitlist);
89
+ expect(actions.primaryActions.length).to.equal(2);
90
+ expect(actions.primaryActions[0].text).to.equal('Borrow for 14 days');
91
+ expect(actions.primaryActions[1].text).to.equal('Leave Waitlist');
92
+
93
+ expect(spy.called).to.be.true;
94
+ });
95
+ it('top of waitlist & can browse', async () => {
96
+ const lendingOptions = new GetLendingActions(
97
+ '@user',
98
+ 'identifier',
99
+ {
100
+ is_lendable: true,
101
+ available_to_borrow: true,
102
+ available_to_browse: true,
103
+ user_can_claim_waitlist: true,
104
+ },
105
+ ''
106
+ );
107
+
108
+ const spy = sinon.spy(lendingOptions, 'claimWaitlistAction');
109
+ const actions = lendingOptions.getCurrentLendingActions();
110
+
111
+ expect(actions.primaryTitle).to.equal(bookTitles.claim_waitlist);
112
+ expect(actions.primaryActions.length).to.equal(3);
113
+ expect(actions.primaryActions[0].text).to.equal('Borrow for 14 days');
114
+ expect(actions.primaryActions[1].text).to.equal('Borrow for 1 hour');
115
+ expect(actions.primaryActions[2].text).to.equal('Leave Waitlist');
116
+ expect(spy.called).to.be.true;
117
+ });
118
+ });
119
+ describe('`user_on_waitlist = true`', () => {
120
+ it('on waitlist && cannot browse', async () => {
121
+ const lendingOptions = new GetLendingActions(
122
+ '@user',
123
+ 'identifier',
124
+ {
125
+ is_lendable: true,
126
+ available_to_borrow: false,
127
+ available_to_browse: false,
128
+ user_can_claim_waitlist: false,
129
+ user_on_waitlist: true,
130
+ },
131
+ ''
132
+ );
133
+
134
+ const claimSpy = sinon.spy(lendingOptions, 'claimWaitlistAction');
135
+ const waitlistSpy = sinon.spy(lendingOptions, 'onWaitlistAction');
136
+ const actions = lendingOptions.getCurrentLendingActions();
137
+
138
+ expect(actions.primaryTitle).to.equal(bookTitles.on_waitlist);
139
+ expect(actions.primaryActions.length).to.equal(2);
140
+ expect(actions.primaryActions[0].text).to.equal('Leave Waitlist');
141
+ expect(actions.primaryActions[1].text).to.equal('Borrow for 1 hour');
142
+ expect(claimSpy.called).to.be.false;
143
+ expect(waitlistSpy.called).to.be.true;
144
+ });
145
+ it('on waitlist && can browse', async () => {
146
+ const lendingOptions = new GetLendingActions(
147
+ '@user',
148
+ 'identifier',
149
+ {
150
+ is_lendable: true,
151
+ available_to_borrow: false,
152
+ available_to_browse: true,
153
+ user_can_claim_waitlist: false,
154
+ user_on_waitlist: true,
155
+ },
156
+ ''
157
+ );
158
+
159
+ const waitlistSpy = sinon.spy(lendingOptions, 'onWaitlistAction');
160
+ const actions = lendingOptions.getCurrentLendingActions();
161
+
162
+ expect(actions.primaryTitle).to.equal(bookTitles.on_waitlist);
163
+ expect(actions.primaryActions.length).to.equal(2);
164
+ expect(actions.primaryActions[0].text).to.equal('Leave Waitlist');
165
+ expect(actions.primaryActions[1].text).to.equal('Borrow for 1 hour');
166
+ expect(waitlistSpy.called).to.be.true;
167
+ });
168
+ });
85
169
  });
86
170
 
87
171
  it('User can access print disabled', async () => {
@@ -99,9 +183,7 @@ describe('Get Lending Actions', () => {
99
183
  const actions = lendingOptions.getCurrentLendingActions();
100
184
 
101
185
  // in-case of print-disabled, we show 14 days borrow
102
- expect(actions.primaryTitle).to.equal(
103
- 'You are eligible for print-disabled access.'
104
- );
186
+ expect(actions.primaryTitle).to.equal(bookTitles.eligible_pd);
105
187
  expect(actions.primaryActions.length).to.equal(1);
106
188
  expect(actions.primaryActions[0].text).to.equal('Borrow for 14 days');
107
189
  });
@@ -117,39 +199,16 @@ describe('Get Lending Actions', () => {
117
199
  );
118
200
  const actions = lendingOptions.getCurrentLendingActions();
119
201
 
120
- expect(actions.primaryTitle).to.equal(
121
- 'Book available to patrons with print disabilities.'
122
- );
202
+ expect(actions.primaryTitle).to.equal(bookTitles.available_pd);
123
203
  expect(actions.primaryActions.length).to.equal(1);
124
204
  expect(actions.primaryActions[0].text).to.equal('Borrow Unavailable');
125
205
  });
126
206
 
127
- it('If user is on waitlist', async () => {
128
- const lendingOptions = new GetLendingActions(
129
- '@user',
130
- 'identifier',
131
- {
132
- user_on_waitlist: true,
133
- user_can_claim_waitlist: false,
134
- },
135
- ''
136
- );
137
- const actions = lendingOptions.getCurrentLendingActions();
138
-
139
- expect(actions.primaryTitle).to.equal(
140
- 'You are on the waitlist for this book.'
141
- );
142
- expect(actions.primaryActions.length).to.equal(2);
143
- expect(actions.primaryActions[0].text).to.equal('Leave Waitlist');
144
- });
145
-
146
207
  it('If book borrow is not available', async () => {
147
208
  const lendingOptions = new GetLendingActions('@user', 'identifier', {}, '');
148
209
  const actions = lendingOptions.getCurrentLendingActions();
149
210
 
150
- expect(actions.primaryTitle).to.equal(
151
- 'This book is not available at this time.'
152
- );
211
+ expect(actions.primaryTitle).to.equal(bookTitles.unavailable);
153
212
  expect(actions.primaryActions.length).to.equal(1);
154
213
  expect(actions.primaryActions[0].text).to.equal('Borrow Unavailable');
155
214
  });