@internetarchive/ia-book-actions 1.4.4-alpha10 → 1.4.4-alpha11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/ia-book-actions.js +37 -11
- package/test/ia-book-actions.test.js +66 -0
package/package.json
CHANGED
package/src/ia-book-actions.js
CHANGED
|
@@ -61,6 +61,7 @@ export default class IABookActions extends LitElement {
|
|
|
61
61
|
modal: { Object },
|
|
62
62
|
tokenDelay: { type: Number },
|
|
63
63
|
timerExecutionSeconds: { type: Number },
|
|
64
|
+
userActionGracePeriod: { type: Number },
|
|
64
65
|
localCache: { type: Object },
|
|
65
66
|
loanRenewTimeConfig: { type: Object },
|
|
66
67
|
loanRenewResult: { type: Object },
|
|
@@ -83,6 +84,14 @@ export default class IABookActions extends LitElement {
|
|
|
83
84
|
this.tokenDelay = 120; // in seconds
|
|
84
85
|
this.timerExecutionSeconds = 30;
|
|
85
86
|
|
|
87
|
+
/**
|
|
88
|
+
* How long (ms) after bindLoanRenewEvents() runs to ignore
|
|
89
|
+
* BookReader:userAction events — BookReader fires that event on its
|
|
90
|
+
* own init-time jump to the last-read page, not just on genuine
|
|
91
|
+
* interaction. @see bindLoanRenewEvents
|
|
92
|
+
*/
|
|
93
|
+
this.userActionGracePeriod = 2000;
|
|
94
|
+
|
|
86
95
|
// private props
|
|
87
96
|
this.postInitComplete = false;
|
|
88
97
|
this.primaryActions = [];
|
|
@@ -283,7 +292,14 @@ export default class IABookActions extends LitElement {
|
|
|
283
292
|
|
|
284
293
|
this.borrowType = actions.borrowType ? actions.borrowType : null;
|
|
285
294
|
|
|
286
|
-
|
|
295
|
+
// Don't (re)start the countdown while a renewal is in flight — the
|
|
296
|
+
// optimistic browsingExpired flip in autoRenewExpiredLoan() (which
|
|
297
|
+
// triggers this same setupLendingToolbarActions() call) happens before
|
|
298
|
+
// renewal is confirmed, so secondsLeftOnLoan could still be a stale
|
|
299
|
+
// value from before the renewal. Wait for handleLoanAutoRenewed() to
|
|
300
|
+
// confirm the real value and clear loanRenewInProgress before showing
|
|
301
|
+
// a countdown again.
|
|
302
|
+
if (this.borrowType === 'browsed' && !this.loanRenewInProgress) {
|
|
287
303
|
// start timer for loan-renew
|
|
288
304
|
await this.startTimerCountdown();
|
|
289
305
|
|
|
@@ -327,10 +343,19 @@ export default class IABookActions extends LitElement {
|
|
|
327
343
|
* 2. IABookActions:loanRenew - dispatched from timer-countdown component
|
|
328
344
|
*/
|
|
329
345
|
bindLoanRenewEvents() {
|
|
346
|
+
this.userActionReadyAt = Date.now() + this.userActionGracePeriod;
|
|
347
|
+
|
|
330
348
|
/**
|
|
331
349
|
* dispatched this event from bookreader page changed
|
|
332
350
|
*/
|
|
333
351
|
window.addEventListener('BookReader:userAction', () => {
|
|
352
|
+
if (Date.now() < this.userActionReadyAt) {
|
|
353
|
+
log(
|
|
354
|
+
'[IABookActions] BookReader:userAction ignored — within startup grace period'
|
|
355
|
+
);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
334
359
|
// Capture before autoRenewExpiredLoan() runs — it synchronously flips
|
|
335
360
|
// lendingStatus.browsingExpired to false as an optimistic UI update,
|
|
336
361
|
// so checking the live property afterward would always see it as
|
|
@@ -448,11 +473,17 @@ export default class IABookActions extends LitElement {
|
|
|
448
473
|
|
|
449
474
|
// Optimistically flip browsingExpired back to false so the action bar
|
|
450
475
|
// stays red (patronIsReadingAction) while the renew_loan request is in
|
|
451
|
-
// flight, instead of showing the blue "Borrow" state.
|
|
476
|
+
// flight, instead of showing the blue "Borrow" state. Deliberately NOT
|
|
477
|
+
// resetting secondsLeftOnLoan here — the renewal hasn't been confirmed
|
|
478
|
+
// yet (it can take several seconds, or genuinely fail), so showing a
|
|
479
|
+
// full hour before we know the outcome would be misleading. The real
|
|
480
|
+
// value is set once handleLoanAutoRenewed() confirms success;
|
|
481
|
+
// loanRenewInProgress (already true above) is the signal consumers
|
|
482
|
+
// should use to show a "renewing" state instead of trusting the
|
|
483
|
+
// countdown during this window.
|
|
452
484
|
this.lendingStatus = {
|
|
453
485
|
...this.lendingStatus,
|
|
454
486
|
browsingExpired: false,
|
|
455
|
-
secondsLeftOnLoan: this.loanRenewTimeConfig.loanTotalTime,
|
|
456
487
|
};
|
|
457
488
|
|
|
458
489
|
// Defer renewNow until after lendingStatus timer setup completes.
|
|
@@ -505,19 +536,14 @@ export default class IABookActions extends LitElement {
|
|
|
505
536
|
headerColor: '#194880',
|
|
506
537
|
showCloseButton: false,
|
|
507
538
|
closeOnBackdropClick: false,
|
|
508
|
-
message: html`<span
|
|
509
|
-
|
|
510
|
-
>
|
|
511
|
-
<span>${this.loanRenewHelper?.getMessageTexts(
|
|
512
|
-
warningTexts,
|
|
513
|
-
secondsLeft
|
|
514
|
-
)}</span>
|
|
539
|
+
message: html`<span>
|
|
540
|
+
${this.loanRenewHelper?.getMessageTexts(warningTexts, secondsLeft)}
|
|
515
541
|
<a
|
|
516
542
|
href="https://help.archive.org/help/borrowing-from-the-lending-library"
|
|
517
543
|
target="_blank"
|
|
518
544
|
title="Get more info on borrowing from The Lending Library"
|
|
519
545
|
data-event-click-tracking="BookReader|BrowsableMoreInfo"
|
|
520
|
-
style="display:inline-
|
|
546
|
+
style="display:inline-block;vertical-align:middle;line-height:0;margin-left:4px;"
|
|
521
547
|
>
|
|
522
548
|
${infoIcon}
|
|
523
549
|
</a>
|
|
@@ -89,6 +89,8 @@ describe('<ia-book-actions>', () => {
|
|
|
89
89
|
identifier: 'foobar',
|
|
90
90
|
})
|
|
91
91
|
);
|
|
92
|
+
// Not testing the BookReader-init grace period here — bypass it.
|
|
93
|
+
el.userActionReadyAt = 0;
|
|
92
94
|
|
|
93
95
|
const spy = Sinon.spy(el, 'autoLoanRenewChecker');
|
|
94
96
|
el.lendingStatus = { ...el.lendingStatus, browsingExpired: false };
|
|
@@ -111,6 +113,8 @@ describe('<ia-book-actions>', () => {
|
|
|
111
113
|
lendingStatus: { user_has_browsed: true, browsingExpired: true },
|
|
112
114
|
})
|
|
113
115
|
);
|
|
116
|
+
// Not testing the BookReader-init grace period here — bypass it.
|
|
117
|
+
el.userActionReadyAt = 0;
|
|
114
118
|
|
|
115
119
|
const spy = Sinon.spy(el, 'autoRenewExpiredLoan');
|
|
116
120
|
el.borrowType = 'browsed';
|
|
@@ -121,6 +125,34 @@ describe('<ia-book-actions>', () => {
|
|
|
121
125
|
|
|
122
126
|
expect(spy.calledOnce).to.be.true;
|
|
123
127
|
});
|
|
128
|
+
|
|
129
|
+
it('ignores BookReader:userAction fired within the startup grace period (WEBDEV-8322 follow-up)', async () => {
|
|
130
|
+
// Regression: BookReader.jumpToIndex() fires its own 'userAction'
|
|
131
|
+
// event any time it runs — including BookReader's own init-time jump
|
|
132
|
+
// to the reader's last-read page (updateFromParams(), called from
|
|
133
|
+
// init()), which has nothing to do with the patron doing anything.
|
|
134
|
+
// Without this grace period, a plain page refresh on an already-
|
|
135
|
+
// expired loan would silently auto-renew before the patron did
|
|
136
|
+
// anything at all.
|
|
137
|
+
const el = await fixture(
|
|
138
|
+
container({
|
|
139
|
+
userid: '@user1',
|
|
140
|
+
identifier: 'foobar',
|
|
141
|
+
lendingStatus: { user_has_browsed: true, browsingExpired: true },
|
|
142
|
+
})
|
|
143
|
+
);
|
|
144
|
+
el.borrowType = 'browsed';
|
|
145
|
+
await el.updateComplete;
|
|
146
|
+
|
|
147
|
+
const spy = Sinon.spy(el, 'autoRenewExpiredLoan');
|
|
148
|
+
|
|
149
|
+
// Fired immediately after bindLoanRenewEvents() ran (in firstUpdated())
|
|
150
|
+
// — well within the default grace period.
|
|
151
|
+
window.dispatchEvent(new Event('BookReader:userAction'));
|
|
152
|
+
await el.updateComplete;
|
|
153
|
+
|
|
154
|
+
expect(spy.called).to.be.false;
|
|
155
|
+
});
|
|
124
156
|
});
|
|
125
157
|
|
|
126
158
|
describe('Primary Actions data', () => {
|
|
@@ -595,6 +627,36 @@ describe('autoRenewExpiredLoan', () => {
|
|
|
595
627
|
expect(el.primaryColor).to.equal('danger');
|
|
596
628
|
});
|
|
597
629
|
|
|
630
|
+
it('does not (re)start the countdown during the optimistic pre-confirmation window (WEBDEV-8322 follow-up)', async () => {
|
|
631
|
+
// Regression: the optimistic browsingExpired flip above triggers
|
|
632
|
+
// setupLendingToolbarActions() before renew_loan is even dispatched,
|
|
633
|
+
// let alone confirmed. Without gating on loanRenewInProgress, that
|
|
634
|
+
// would (re)start the timer-countdown interval using whatever stale
|
|
635
|
+
// secondsLeftOnLoan was left over from before the loan expired,
|
|
636
|
+
// showing a wrong/flickering value until handleLoanAutoRenewed()
|
|
637
|
+
// corrects it moments later.
|
|
638
|
+
const el = await fixture(
|
|
639
|
+
container({
|
|
640
|
+
userid: '@user1',
|
|
641
|
+
identifier: 'foobar',
|
|
642
|
+
lendingStatus: {
|
|
643
|
+
user_has_browsed: true,
|
|
644
|
+
available_to_browse: true,
|
|
645
|
+
browsingExpired: true,
|
|
646
|
+
},
|
|
647
|
+
})
|
|
648
|
+
);
|
|
649
|
+
await el.updateComplete;
|
|
650
|
+
|
|
651
|
+
const startTimerCountdownSpy = Sinon.spy(el, 'startTimerCountdown');
|
|
652
|
+
|
|
653
|
+
el.autoRenewExpiredLoan();
|
|
654
|
+
await el.updateComplete;
|
|
655
|
+
|
|
656
|
+
expect(el.loanRenewInProgress).to.be.true;
|
|
657
|
+
expect(startTimerCountdownSpy.called).to.be.false;
|
|
658
|
+
});
|
|
659
|
+
|
|
598
660
|
it('sets loanRenewInProgress and triggers renewNow after timeout', async () => {
|
|
599
661
|
const el = await fixture(
|
|
600
662
|
container({
|
|
@@ -882,6 +944,8 @@ describe('BookReader:userAction race regression (WEBDEV-8322)', () => {
|
|
|
882
944
|
);
|
|
883
945
|
await el.updateComplete;
|
|
884
946
|
expect(el.borrowType).to.equal('browsed');
|
|
947
|
+
// Not testing the BookReader-init grace period here — bypass it.
|
|
948
|
+
el.userActionReadyAt = 0;
|
|
885
949
|
|
|
886
950
|
el.lendingStatus = { ...baseStatus, browsingExpired: true };
|
|
887
951
|
await el.updateComplete;
|
|
@@ -923,6 +987,8 @@ describe('BookReader:userAction race regression (WEBDEV-8322)', () => {
|
|
|
923
987
|
);
|
|
924
988
|
await el.updateComplete;
|
|
925
989
|
expect(el.borrowType).to.equal('browsed');
|
|
990
|
+
// Not testing the BookReader-init grace period here — bypass it.
|
|
991
|
+
el.userActionReadyAt = 0;
|
|
926
992
|
|
|
927
993
|
el.loanRenewInProgress = true;
|
|
928
994
|
|