LP#1673870: fix bug that prevented more than one ebook transaction from appearing...
[working/Evergreen.git] / Open-ILS / web / js / ui / default / opac / ebook_api / loggedin.js
1 /*
2  * variables defined in base_js.tt2:
3  *
4  * ou
5  * vendor_list = [ 'ebook_test' ]
6  * authtoken
7  * patron_id (barcode)
8  * myopac_page
9  * progress_icon (probably not done right)
10  *
11  * base_js.tt2 also "imports" dojo.cookie and a bunch of ebook_api JS
12  */
13
14 // Array of objects representing this patron's relationship with a specific vendor.
15 var relations = [];
16
17 // Transaction cache.
18 var xacts = {
19     checkouts: [],
20     holds_pending: [],
21     holds_ready: []
22 };
23
24 // Ebook to perform actions on.
25 var active_ebook;
26 if (typeof ebook_action.title_id !== 'undefined') {
27     active_ebook = new Ebook(ebook_action.vendor, ebook_action.title_id);
28 }
29
30 dojo.addOnLoad(function() {
31
32     dojo.forEach(vendor_list, function(v) {
33         var rel = new Relation(v, patron_id);
34         relations.push(rel);
35     });
36
37     // Pull patron transaction info from cache (cookie), if available.
38     // Otherwise, do a live lookup against all enabled vendors.
39     if (dojo.cookie('ebook_xact_cache')) {
40         getCachedTransactions();
41         addTotalsToPage();
42         addTransactionsToPage();
43     } else {
44         console.log('retrieving patron transaction info for all vendors');
45         dojo.forEach(relations, function(rel) {
46             checkSession(rel.vendor, function(ses) {
47                 rel.getTransactions( function(r) {
48                     addTransactionsToCache(r);
49                 });
50             });
51         });
52     }
53
54 });
55
56 // Update current page with cross-vendor transaction totals.
57 function addTotalsToPage() {
58     console.log('updating page with transaction totals');
59     updateDashboard();
60     updateMyAccountSummary();
61 }
62
63 // Update current page with detailed transaction info, where appropriate.
64 function addTransactionsToPage() {
65     if (myopac_page) {
66         console.log('updating page with cached transaction details, if applicable');
67         if (myopac_page === 'ebook_circs')
68             updateCheckoutView();
69         if (myopac_page === 'ebook_holds')
70             updateHoldView();
71         if (myopac_page === 'ebook_holds_ready')
72             updateHoldView();
73         if (myopac_page === 'ebook_checkout')
74             getReadyForCheckout();
75         if (myopac_page === 'ebook_place_hold')
76             getReadyForHold();
77     }
78 }
79         
80 function updateDashboard() {
81     console.log('updating dashboard');
82     var total_checkouts = (typeof xacts.checkouts === 'undefined') ? '-' : xacts.checkouts.length;
83     var total_holds_pending = (typeof xacts.holds_pending === 'undefined') ? '-' : xacts.holds_pending.length;
84     var total_holds_ready = (typeof xacts.holds_ready === 'undefined') ? '-' : xacts.holds_ready.length;
85     // update totals
86     dojo.byId('dash_e_checked').innerHTML = total_checkouts;
87     dojo.byId('dash_e_holds').innerHTML = total_holds_pending;
88     dojo.byId('dash_e_pickup').innerHTML = total_holds_ready;
89     // unhide ebook dashboard
90     dojo.removeClass('dashboard_e', "hidden");
91 }
92
93 function updateMyAccountSummary() {
94     if (myopac_page === 'main') {
95         console.log('updating account summary');
96         var total_checkouts = (typeof xacts.checkouts === 'undefined') ? '-' : xacts.checkouts.length;
97         var total_holds_pending = (typeof xacts.holds_pending === 'undefined') ? '-' : xacts.holds_pending.length;
98         var total_holds_ready = (typeof xacts.holds_ready === 'undefined') ? '-' : xacts.holds_ready.length;
99         // update totals
100         dojo.byId('acct_sum_ebook_circ_total').innerHTML = total_checkouts;
101         dojo.byId('acct_sum_ebook_hold_total').innerHTML = total_holds_pending;
102         dojo.byId('acct_sum_ebook_hold_ready_total').innerHTML = total_holds_ready;
103         // unhide display elements
104         dojo.removeClass('acct_sum_ebook_circs', "hidden");
105         dojo.removeClass('acct_sum_ebook_holds', "hidden");
106         dojo.removeClass('acct_sum_ebook_holds_ready', "hidden");
107     }
108 }
109
110 function updateCheckoutView() {
111     if (xacts.checkouts.length < 1) {
112         dojo.removeClass('no_ebook_circs', "hidden");
113     } else {
114         dojo.empty('ebook_circs_main_table_body');
115         dojo.forEach(xacts.checkouts, function(x) {
116             var dl_link = '<a href="' + x.download_url + '">' + l_strings.download + '</a>';
117             var tr = dojo.create("tr", null, dojo.byId('ebook_circs_main_table_body'));
118             dojo.create("td", { innerHTML: x.title }, tr);
119             dojo.create("td", { innerHTML: x.author }, tr);
120             dojo.create("td", { innerHTML: x.due_date }, tr);
121             dojo.create("td", { innerHTML: dl_link}, tr);
122             // TODO: more actions (renew, checkin)
123         });
124         dojo.addClass('no_ebook_circs', "hidden");
125         dojo.removeClass('ebook_circs_main', "hidden");
126     }
127 }
128
129 function updateHoldView() {
130     if (myopac_page === 'ebook_holds_ready') {
131         // only show holds that are ready for checkout
132         var holds = xacts.holds_ready;
133     } else {
134         var holds_pending = xacts.holds_pending;
135         var holds_ready = xacts.holds_ready;
136
137         // combine all holds into a single list, ready-for-checkout holds first
138         var holds = holds_ready.concat(holds_pending);
139     }
140
141     if (holds.length < 1) {
142         dojo.removeClass('no_ebook_holds', "hidden");
143     } else {
144         dojo.empty('ebook_holds_main_table_body');
145         dojo.forEach(holds, function(h) {
146             var hold_status;
147             if (h.is_ready) {
148                 hold_status = l_strings.ready_for_checkout;
149             } else if (h.is_frozen) {
150                 hold_status = l_strings.suspended;
151             } else {
152                 hold_status = h.queue_position + ' / ' + h.queue_size;
153             }
154             h.doCancelHold = function() {
155                 var ebook = new Ebook(this.vendor, this.title_id);
156                 ebook.cancelHold(authtoken, patron_id, function(resp) {
157                     if (resp.error_msg) {
158                         console.log('Cancel hold failed: ' . resp.error_msg);
159                         dojo.removeClass('ebook_cancel_hold_failed', "hidden");
160                     } else {
161                         console.log('Cancel hold succeeded!');
162                         dojo.destroy("hold-" + ebook.id);
163                         dojo.removeClass('ebook_cancel_hold_succeeded', "hidden");
164                         // Updating the transaction cache to remove the canceled hold
165                         // is inconvenient, so we skip cleanupAfterAction() and merely
166                         // clear transaction cache to force a refresh on next page load.
167                         dojo.cookie('ebook_xact_cache', '', {path: '/', expires: '-1h'});
168                     }
169                 });
170             };
171             var tr = dojo.create("tr", { id: "hold-" + h.title_id }, dojo.byId('ebook_holds_main_table_body'));
172             dojo.create("td", { innerHTML: h.title }, tr);
173             dojo.create("td", { innerHTML: h.author }, tr);
174             dojo.create("td", { innerHTML: h.expire_date }, tr);
175             dojo.create("td", { innerHTML: hold_status }, tr);
176             var actions_td = dojo.create("td", null, tr);
177             var button = dojo.create("input", { id: "cancel-hold-" + h.title_id, type: "button", value: l_strings.cancel_hold }, actions_td);
178             dojo.connect(button, 'onclick', h, "doCancelHold");
179         });
180         dojo.addClass('no_ebook_holds', "hidden");
181         dojo.removeClass('ebook_holds_main', "hidden");
182     }
183 }
184
185 // set up page for user to perform a checkout
186 function getReadyForCheckout() {
187     if (typeof active_ebook === 'undefined') {
188         console.log('No active ebook specified, cannot prepare for checkout');
189         dojo.removeClass('ebook_checkout_failed', "hidden");
190     } else {
191         active_ebook.getDetails( function(ebook) {
192             dojo.empty('ebook_circs_main_table_body');
193             var tr = dojo.create("tr", null, dojo.byId('ebook_circs_main_table_body'));
194             dojo.create("td", { innerHTML: ebook.title }, tr);
195             dojo.create("td", { innerHTML: ebook.author }, tr);
196             dojo.create("td", null, tr);
197             dojo.create("td", { id: "checkout-button-td" }, tr);
198             var button = dojo.create("input", { id: "checkout-button", type: "button", value: l_strings.checkout }, dojo.byId('checkout-button-td'));
199             ebook.conns.checkout = dojo.connect(button, 'onclick', "doCheckout");
200             dojo.removeClass('ebook_circs_main', "hidden");
201         });
202     }
203 }
204
205 // set up page for user to place a hold
206 function getReadyForHold() {
207     if (typeof active_ebook === 'undefined') {
208         console.log('No active ebook specified, cannot prepare for hold');
209         dojo.removeClass('ebook_hold_failed', "hidden");
210     } else {
211         active_ebook.getDetails( function(ebook) {
212             dojo.empty('ebook_holds_main_table_body');
213             var tr = dojo.create("tr", null, dojo.byId('ebook_holds_main_table_body'));
214             dojo.create("td", { innerHTML: ebook.title }, tr);
215             dojo.create("td", { innerHTML: ebook.author }, tr);
216             dojo.create("td", null, tr); // Expire Date
217             dojo.create("td", null, tr); // Status
218             dojo.create("td", { id: "hold-button-td" }, tr);
219             if (ebook_action.type == 'place_hold') {
220                 var button = dojo.create("input", { id: "hold-button", type: "button", value: l_strings.place_hold }, dojo.byId('hold-button-td'));
221                 ebook.conns.checkout = dojo.connect(button, 'onclick', "doPlaceHold");
222             }
223             dojo.removeClass('ebook_holds_main', "hidden");
224         });
225     }
226 }
227
228 function cleanupAfterAction() {
229     // unset variables related to the transaction we have performed,
230     // to avoid any weirdness on page reload
231     ebook_action = {};
232     // update page to account for successful checkout
233     addTotalsToPage();
234     addTransactionsToPage();
235     // clear transaction cache to force a refresh on next page load
236     dojo.cookie('ebook_xact_cache', '', {path: '/', expires: '-1h'});
237 }
238
239 // check out our active ebook
240 function doCheckout() {
241     active_ebook.checkout(authtoken, patron_id, function(resp) {
242         if (resp.due_date) {
243             console.log('Checkout succeeded!');
244             dojo.destroy('checkout-button');
245             dojo.removeClass('ebook_checkout_succeeded', "hidden");
246             // add our successful checkout to top of transaction cache
247             var new_xact = {
248                 title_id: active_ebook.id,
249                 title: active_ebook.title,
250                 author: active_ebook.author,
251                 due_date: resp.due_date,
252                 download_url: '' // TODO - for OverDrive, user must "lock in" a format first!
253             };
254             xacts.checkouts.unshift(new_xact);
255             cleanupAfterAction();
256         } else {
257             console.log('Checkout failed: ' + resp.error_msg);
258             dojo.removeClass('ebook_checkout_failed', "hidden");
259         }
260         // When we switch to jQuery, we can use .one() instead of .on(),
261         // obviating the need for an explicit disconnect here.
262         dojo.disconnect(active_ebook.conns.checkout);
263     });
264 }
265
266 // place hold on our active ebook
267 function doPlaceHold() {
268     active_ebook.placeHold(authtoken, patron_id, function(resp) {
269         if (resp.error_msg) {
270             console.log('Place hold failed: ' . resp.error_msg);
271             dojo.removeClass('ebook_place_hold_failed', "hidden");
272         } else {
273             console.log('Place hold succeeded!');
274             dojo.destroy('hold-button');
275             dojo.removeClass('ebook_place_hold_succeeded', "hidden");
276             var new_hold = {
277                 title_id: active_ebook.id,
278                 title: active_ebook.title,
279                 author: active_ebook.author,
280                 queue_position: resp.queue_position,
281                 queue_size: resp.queue_size,
282                 expire_date: resp.expire_date
283             };
284             if ( resp.is_ready || (resp.queue_position === 1 && resp.queue_size === 1) ) {
285                 xacts.holds_ready.unshift(new_hold);
286             } else {
287                 xacts.holds_pending.unshift(new_hold);
288             }
289             cleanupAfterAction();
290         }
291     });
292 }
293
294 // deserialize transactions from cache, returning them as a JS object
295 function getCachedTransactions() {
296     console.log('retrieving cached transaction details');
297     var cache_obj;
298     var current_cache = dojo.cookie('ebook_xact_cache');
299     if (current_cache) {
300         cache_obj = JSON.parse(current_cache);
301         xacts.checkouts = cache_obj.checkouts;
302         xacts.holds_pending = cache_obj.holds_pending;
303         xacts.holds_ready = cache_obj.holds_ready;
304     }
305     return cache_obj;
306 }
307
308 // add a single vendor's transactions to transaction cache
309 function addTransactionsToCache(rel) {
310     console.log('updating transaction cache');
311     var v = rel.vendor;
312     var updated_xacts = {
313         checkouts: [],
314         holds_pending: [],
315         holds_ready: []
316     };
317     // preserve any transactions with other vendors
318     dojo.forEach(xacts.checkouts, function(xact) {
319         if (xact.vendor !== v)
320             updated_xacts.checkouts.push(xact);
321     });
322     dojo.forEach(xacts.holds_pending, function(xact) {
323         if (xact.vendor !== v)
324             updated_xacts.holds_pending.push(xact);
325     });
326     dojo.forEach(xacts.holds_ready, function(xact) {
327         if (xact.vendor !== v)
328             updated_xacts.holds_ready.push(xact);
329     });
330     // add transactions from current vendor
331     dojo.forEach(rel.checkouts, function(xact) {
332         updated_xacts.checkouts.push(xact);
333     });
334     dojo.forEach(rel.holds_pending, function(xact) {
335         updated_xacts.holds_pending.push(xact);
336     });
337     dojo.forEach(rel.holds_ready, function(xact) {
338         updated_xacts.holds_ready.push(xact);
339     });
340     // TODO sort transactions by date
341     // save transactions to cache
342     xacts = updated_xacts;
343     var new_cache = JSON.stringify(xacts);
344     dojo.cookie('ebook_xact_cache', new_cache, {path: '/'});
345     // update current page
346     addTotalsToPage();
347     addTransactionsToPage();
348 }
349