(function (context, $) { "use strict"; context.JK = context.JK || {}; context.JK.CheckoutOrderScreen = function (app) { var EVENTS = context.JK.EVENTS; var logger = context.JK.logger; var rest = context.JK.Rest(); var jamTrackUtils = context.JK.JamTrackUtils; var checkoutUtils = context.JK.CheckoutUtilsInstance; var $screen = null; var $navigation = null; var $templateOrderContent = null; var $templatePurchasedJamTrack = null; var $orderPanel = null; var $thanksPanel = null; var $jamTrackInBrowser = null; var $purchasedJamTrack = null; var $purchasedJamTrackHeader = null; var $purchasedJamTracks = null; var $orderContent = null; var userDetail = null; var step = null; var downloadJamTracks = []; var purchasedJamTracks = null; var purchasedJamTrackIterator = 0; var $backBtn = null; var $orderPrompt = null; var $emptyCartPrompt = null; var $noAccountInfoPrompt = null; var $downloadApplicationLink = null; function beforeShow() { } function afterShow(data) { beforeShowOrder(); } function beforeHide() { if(downloadJamTracks) { context._.each(downloadJamTracks, function(downloadJamTrack) { downloadJamTrack.destroy(); downloadJamTrack.root.remove(); }) downloadJamTracks = []; } purchasedJamTracks = null; purchasedJamTrackIterator = 0; } function beforeShowOrder() { $purchasedJamTracks.empty() $orderPrompt.addClass('hidden') $emptyCartPrompt.addClass('hidden') $noAccountInfoPrompt.addClass('hidden') $orderPanel.removeClass("hidden") $thanksPanel.addClass("hidden") $purchasedJamTrackHeader.attr('status', 'in-progress') $screen.find(".place-order").addClass('disabled').off('click', placeOrder) $("#order_error").text('').addClass("hidden") step = 3; renderNavigation(); populateOrderPage(); } function populateOrderPage() { clearOrderPage(); rest.getShoppingCarts() .done(function(carts) { rest.getBillingInfo() .done(function(billingInfo) { renderOrderPage(carts, billingInfo) }) .fail(function(jqXHR) { if(jqXHR.status == 404) { // no account for this user $noAccountInfoPrompt.removeClass('hidden') app.notify({ title: "No account information", text: "Please restart the checkout process." }, null, true); } }) }) .fail(app.ajaxError); } function renderOrderPage(carts, recurlyAccountInfo) { logger.debug("rendering order page") var data = {} var sub_total = 0.0 var taxes = 0.0 $.each(carts, function(index, cart) { sub_total += parseFloat(cart.product_info.real_price) }); if(carts.length == 0) { data.grand_total = '-.--' data.sub_total = '-.--' data.taxes = '-.--' data.shipping_handling = '-.--' } else { data.grand_total = 'Calculating...' data.sub_total = '$' + sub_total.toFixed(2) data.taxes = 'Calculating...' data.shipping_handling = '$0.00' } data.carts = carts data.billing_info = recurlyAccountInfo.billing_info data.shipping_info = recurlyAccountInfo.address data.shipping_as_billing = true; //jamTrackUtils.compareAddress(data.billing_info, data.shipping_info); var orderContentHtml = $( context._.template( $templateOrderContent.html(), data, {variable: 'data'} ) ) $orderContent.append(orderContentHtml) $orderPanel.find(".change-payment-info").on('click', moveToPaymentInfo) var $placeOrder = $screen.find(".place-order") if(carts.length == 0) { $orderPrompt.addClass('hidden') $emptyCartPrompt.removeClass('hidden') $noAccountInfoPrompt.addClass('hidden') $placeOrder.addClass('disabled').unbind('click').on('click', false) } else { logger.debug("cart has " + carts.length + " items in it") $orderPrompt.removeClass('hidden') $emptyCartPrompt.addClass('hidden') $noAccountInfoPrompt.addClass('hidden') if(gon.global.purchases_enabled || context.JK.currentUserAdmin) { $placeOrder.removeClass('disabled').unbind('click').on('click', placeOrder) } else { $placeOrder.addClass('disabled').unbind('click').on('click', false) } estimateTaxes(carts, recurlyAccountInfo.billing_info); } } function displayTax(effectiveQuantity, item_tax, total_with_tax) { var totalTax = 0; var totalPrice = 0; var unitTax = item_tax * effectiveQuantity; totalTax += unitTax; var totalUnitPrice = total_with_tax * effectiveQuantity; totalPrice += totalUnitPrice; $screen.find('.order-right-page .order-items-value.taxes').text('$' + totalTax.toFixed(2)) $screen.find('.order-right-page .order-items-value.grand-total').text('$' + totalPrice.toFixed(2)) } function estimateTaxes(carts, billing_info) { var planPricing = {} var priceElement = $screen.find('.order-right-page .plan.jamtrack') if(priceElement.length == 0) { logger.error("unable to find price element for jamtrack"); app.notify({title: "Error Encountered", text: "Unable to find plan info for jam track"}) return false; } logger.debug("creating recurly pricing element for plan: " + gon.recurly_tax_estimate_jam_track_plan) var effectiveQuantity = 0 context._.each(carts, function(cart) { effectiveQuantity += cart.product_info.quantity - cart.product_info.marked_for_redeem }) if (gon.global.estimate_taxes) { var state = billing_info.state; var country = billing_info.country; if (state) { state = state.toLowerCase(); } if (country) { country = country.toLowerCase(); } var taxRate = 0; if (state && country && (state == 'tx' || state == 'texas') && country == 'us') { taxRate = 0.0825; } var unitTax = 1.99 * taxRate; displayTax(effectiveQuantity, unitTax, 1.99 + unitTax) } else { var pricing = context.recurly.Pricing(); pricing.plan_code = gon.recurly_tax_estimate_jam_track_plan; pricing.resolved = false; pricing.effective_quantity = 1 // this is called when the plan is resolved against Recurly. It will have tax info, which is the only way we can get it. pricing.on('change', function(price) { logger.debug("pricing", pricing) displayTax(effectiveQuantity, Number(pricing.price.now.tax), Number(pricing.price.now.total)); }) pricing.attach(priceElement.eq(0)) } } function moveToPaymentInfo() { context.location = '/client#/checkoutPayment'; return false; } function placeOrder(e) { e.preventDefault(); $screen.find(".place-order").off('click').addClass('disabled') $("#order_error").text('').addClass("hidden") rest.placeOrder() .done(moveToThanks) .fail(orderErrorHandling); } function orderErrorHandling(xhr, ajaxOptions, thrownError) { if (xhr && xhr.responseJSON) { var message = "Error submitting payment: " $.each(xhr.responseJSON.errors, function (key, error) { message += key + ": " + error }) $("#order_error").text(message).removeClass("hidden") } else { $("#order_error").text(xhr.responseText).removeClass("hidden") } $screen.find(".place-order").on('click', placeOrder).removeClass('disabled') } function moveToThanks(purchaseResponse) { checkoutUtils.deletePreserveBillingInfo() $("#order_error").addClass("hidden") $orderPanel.addClass("hidden") $thanksPanel.removeClass("hidden") jamTrackUtils.checkShoppingCart() app.refreshUser() handleJamTracksPurchased(purchaseResponse.jam_tracks) } function handleJamTracksPurchased(jamTracks) { // were any JamTracks purchased? var jamTracksPurchased = jamTracks && jamTracks.length > 0; if(jamTracksPurchased) { if(gon.isNativeClient) { startDownloadJamTracks(jamTracks) } else { $jamTrackInBrowser.removeClass('hidden'); app.user().done(function(user) { if(!user.first_downloaded_client_at) { $downloadApplicationLink.removeClass('hidden') } }) } } } function startDownloadJamTracks(jamTracks) { // there can be multiple purchased JamTracks, so we cycle through them purchasedJamTracks = jamTracks; // populate list of jamtracks purchased, that we will iterate through graphically context._.each(jamTracks, function(jamTrack) { var downloadJamTrack = new context.JK.DownloadJamTrack(app, jamTrack, 'small'); var $purchasedJamTrack = $(context._.template( $templatePurchasedJamTrack.html(), jamTrack, {variable: 'data'} )); $purchasedJamTracks.append($purchasedJamTrack) // show it on the page $purchasedJamTrack.append(downloadJamTrack.root) downloadJamTracks.push(downloadJamTrack) }) iteratePurchasedJamTracks(); } function iteratePurchasedJamTracks() { if(purchasedJamTrackIterator < purchasedJamTracks.length ) { var downloadJamTrack = downloadJamTracks[purchasedJamTrackIterator++]; // make sure the 'purchasing JamTrack' section can be seen $purchasedJamTrack.removeClass('hidden'); // the widget indicates when it gets to any transition; we can hide it once it reaches completion $(downloadJamTrack).on(EVENTS.JAMTRACK_DOWNLOADER_STATE_CHANGED, function(e, data) { if(data.state == downloadJamTrack.states.synchronized) { logger.debug("jamtrack " + downloadJamTrack.jamTrack.name + " synchronized;") //downloadJamTrack.root.remove(); downloadJamTrack.destroy(); // go to the next JamTrack iteratePurchasedJamTracks() } }) logger.debug("jamtrack " + downloadJamTrack.jamTrack.name + " downloader initializing") // kick off the download JamTrack process downloadJamTrack.init() // XXX style-test code // downloadJamTrack.transitionError("package-error", "The server failed to create your package.") } else { logger.debug("done iterating over purchased JamTracks") $purchasedJamTrackHeader.attr('status', 'done') } } function clearOrderPage() { $orderContent.empty(); } function renderNavigation() { $navigation.html(""); var navigationHtml = $( context._.template( $('#template-checkout-navigation').html(), {current: step, purchases_disable_class: gon.global.purchases_enabled ? 'hidden' : ''}, {variable: 'data'} ) ); $navigation.append(navigationHtml); } function events() { $backBtn.on('click', function(e) { e.preventDefault(); context.location = '/client#/checkoutPayment' }) } function initialize() { var screenBindings = { 'beforeShow': beforeShow, 'afterShow': afterShow, 'beforeHide': beforeHide }; app.bindScreen('checkoutOrder', screenBindings); $screen = $("#checkoutOrderScreen"); $navigation = $screen.find(".checkout-navigation-bar"); $templateOrderContent = $("#template-order-content"); $templatePurchasedJamTrack = $('#template-purchased-jam-track'); $orderPanel = $screen.find(".order-panel"); $thanksPanel = $screen.find(".thanks-panel"); $jamTrackInBrowser = $screen.find(".thanks-detail.jam-tracks-in-browser"); $purchasedJamTrack = $thanksPanel.find(".thanks-detail.purchased-jam-track"); $purchasedJamTrackHeader = $purchasedJamTrack.find(".purchased-jam-track-header"); $purchasedJamTracks = $purchasedJamTrack.find(".purchased-list") $backBtn = $screen.find('.back'); $orderPrompt = $screen.find('.order-prompt'); $emptyCartPrompt = $screen.find('.empty-cart-prompt'); $noAccountInfoPrompt = $screen.find('.no-account-info-prompt'); $orderContent = $orderPanel.find(".order-content"); $downloadApplicationLink = $screen.find('.download-jamkazam-wrapper'); if ($screen.length == 0) throw "$screen must be specified"; if ($navigation.length == 0) throw "$navigation must be specified"; events(); } this.initialize = initialize; return this; } }) (window, jQuery);