/* adds sherpa location checker to cart page (c) Min Liu 2020 */ (function () { var sherpaLang = { "widget-selectshipping-title": "Select shipping method", "widget-selectshipping-desc": "Costs will be calculated at checkout", "widget-selectshipping-button-sherpa": "Local delivery by Sherpa", "widget-selectshipping-button-sherpa-desc": "Delivery at a specified date & time. Checks items are available. Other shipping options may also be shown at checkout", "widget-selectshipping-button-shipping": "Other shipping methods", "widget-selectshipping-button-shipping-desc": "Displays all other shipping options at checkout", "widget-checkpostcode-title": "Check delivery eligibility", "widget-checkpostcode-desc": "Enter your postcode to see if all items in your cart are available for local delivery.", "widget-input-placeholder": "Enter your postcode to check if we can deliver", "widget-invalid-postcode": "Please double check you have entered a valid postcode.", "widget-all-fulfillable": "Great! Items in your cart are available for local delivery.", "widget-none-fulfillable": "Local delivery not available to your location. Other shipping options, if available, will be shown at checkout.", "widget-no-rates": "Local delivery not available to your location. Other shipping options, if available, will be shown at checkout.", "widget-removed-offending": "Items not available for local delivery to your location have been removed from your cart.", "widget-calendar-placeholder": "Select a date", "widget-delivery-notes-title": "Note for delivery driver", "widget-delivery-notes-placeholder": "Add note", "modal-title": "Local delivery is not available for some items", "modal-desc": "Please remove these items to proceed", "modal-button": "Remove items and continue", "modal-skip-button": "Skip this step - other shipping options will be shown at checkout", }; var checkoutItems = {}; var itemsToRemove = []; var checkoutSelector = "[name='checkout']"; var sherpaIdVar = '_sherpaid'; var showLocationWidget = false; var showCalendarWidget = true; var showDeliveryNotes = false; var calendarBlockoutDates = []; var allowPopupSkip = false; var selectedDate = null; var selectedLocation = null; var shipWithSherpa = false; var checkCartTags = function($) { console.log('checkCartTags'); var inflight = 0; var hasExcludeTag = false; $.ajax({ type: "GET", url: "/cart.js", processData: false, dataType: 'json', async: false, success: function(cart) { $(cart.items).each(function(k,v) { inflight += 1; $.ajax({ type: "GET", url: "/products/"+v.handle+".js", processData: false, dataType: 'json', async: true, success: function(product) { inflight -= 1; if (product.tags.indexOf('sherpa-exclude') > -1) { hasExcludeTag = true; } if (inflight == 0) { if (hasExcludeTag) { console.log('skip UI: has sherpa-exclude'); //re-enable checkout button $(checkoutSelector).prop('disabled',false).removeClass('disabled'); } else { initUIElements($); } } } }); }); } }); }; var addCartToken = function($,forceUpdate) { console.log('addCartToken'); if (typeof forceUpdate == 'undefined') force = false; var cartToken = null; var cartData = {}; //get current cart $.ajax({ type: "GET", url: "/cart.js", processData: false, dataType: 'json', async: false, success: function(cart) { //set on all items in the cart that requires shipping cartToken = cart.token; console.log('cart token: '+cartToken); var sherpaID = 'T='+cartToken; if (showCalendarWidget) { sherpaID = sherpaID+'&D='+selectedDate; } sherpaID = sherpaID+'&TS='+Date.now(); for (idx=0; idx < cart.items.length; idx++) { var item = cart.items[idx]; if (item.requires_shipping && (!(item.properties && item.properties[sherpaIdVar] && item.properties[sherpaIdVar] != '') || forceUpdate)) { cartData.line = idx+1; cartData.quantity = item.quantity; cartData.properties = item.properties; if (cartData.properties === null) { //no existing properties cartData.properties = {}; cartData.properties[sherpaIdVar] = sherpaID; } else { cartData.properties[sherpaIdVar] = sherpaID; } $.ajax({ url: '/cart/sherpachange.js', type: 'POST', dataType: 'json', data: cartData, async: false, complete: function(data) { console.log('line item updated'); } }); } } } }); }; var removeCartToken = function($) { console.log('removeCartToken'); //get current cart $.ajax({ type: "GET", url: "/cart.js", processData: false, dataType: 'json', async: false, success: function(cart) { for (idx=0; idx < cart.items.length; idx++) { var item = cart.items[idx]; if (item.properties && item.properties[sherpaIdVar]) { console.log('property requires removing: '+(idx+1)); var cartData = {}; cartData.line = idx+1; cartData.quantity = item.quantity; cartData.properties = item.properties; cartData.properties[sherpaIdVar] = ''; $.ajax({ url: '/cart/sherpachange.js', type: 'POST', dataType: 'json', data: cartData, async: false, success: function(data) { console.log('removed property line: '+cartData.line); } }); } } } }); }; var showNextStep = function($,currentStep) { if (currentStep == 'SHOWEND') { $(checkoutSelector).prop('disabled',false).removeClass('disabled'); } if (currentStep == 'LOCATION') { if (showCalendarWidget && shipWithSherpa) { $('.sherpa-wrapper-calendar').show(); } else { if (shipWithSherpa) $('.sherpa-wrapper-deliverynotes').show(); $(checkoutSelector).prop('disabled',false).removeClass('disabled'); } } if (currentStep == 'CALENDAR') { $(checkoutSelector).prop('disabled',false).removeClass('disabled'); $('.sherpa-wrapper-deliverynotes').show(); } }; var getDateStr = function(date) { var _day = date.getDate()+''; var _month = (date.getMonth()+1)+''; if (_day.length == 1) _day = '0'+_day; if (_month.length == 1) _month = '0'+_month; return date.getFullYear()+'-'+_month+'-'+_day; }; var dateFormatddmmyyyy = function(date) { var day = date.getDate()+""; var month = (date.getMonth()+1)+""; var year = date.getFullYear(); if (day.length == 1) day = '0'+day; if (month.length == 1) month = '0'+month; return day+'/'+month+'/'+year; }; var calendarAvailDOW = []; var isDateValid = function($,date,cutoffTimeDOW,_readyTS) { var dow = new Array(7); dow[0] = "sun"; dow[1] = "mon"; dow[2] = "tue"; dow[3] = "wed"; dow[4] = "thu"; dow[5] = "fri"; dow[6] = "sat"; // console.log('selected location: '+selectedLocation+', date: '+getDateStr(date)); cutoffTimeLoc = selectedLocation; if (cutoffTimeLoc === null || typeof cutoffTimeDOW[cutoffTimeLoc] === 'undefined') cutoffTimeLoc = 'DEFAULT'; blockoutLoc = selectedLocation; if (blockoutLoc === null || typeof calendarBlockoutDates[blockoutLoc] === 'undefined') blockoutLoc = 'DEFAULT'; var mydow = dow[date.getDay()]; var mydateStr = getDateStr(date); var _date = new Date(date.getTime()); //check business hour dow if (calendarAvailDOW.length > 0) { if (!calendarAvailDOW[mydow]) { return false; } } //check blockout date if (typeof calendarBlockoutDates[blockoutLoc] !== 'undefined' && calendarBlockoutDates[blockoutLoc].includes(mydateStr)) { return false; } if (cutoffTimeDOW[cutoffTimeLoc][mydow] === false) { return false; } else { var matches = cutoffTimeDOW[cutoffTimeLoc][mydow].match(/(\d+)(\d\d)$/); var windowEndHr = parseInt(matches[1]); var windowEndMin = parseInt(matches[2]); _date.setHours(windowEndHr,windowEndMin); if ((_date.getTime()/1000) < _readyTS) { //is today and after cutoff time return false; } else { return true; } } }; var _postcodeAutoSubmitTimer = null; var initUI = function($) { if ($(checkoutSelector).length > 0) { //disable checkout button $(checkoutSelector).prop('disabled',true).addClass('disabled'); checkCartTags($); } }; var initUIElements = function($) { console.log('cart page found'); addAjaxHooks($); //add css var css = document.createElement('link'); css.rel = 'stylesheet'; css.type = 'text/css'; css.href = '//plugin-app.sherpa.net.au/css/widget.css?20211124'; $('head').append(css) //disable checkout button $(checkoutSelector).prop('disabled',true).addClass('disabled'); var css = document.createElement('link'); css.rel = 'stylesheet'; css.type = 'text/css'; css.href = '//plugin-app.sherpa.net.au/css/jquery-ui.min.css?20211124'; $('head').append(css) var html = $(""); var insertionPoint = $(checkoutSelector); //check to see if there is a cart__actions if ($(insertionPoint).closest('.cart__actions').length > 0) { insertionPoint = $(insertionPoint).closest('.cart__actions'); } $(insertionPoint).before(html); //show the postcode checker widget if (showLocationWidget) { //add widget console.log('load multi-location widget'); var html = $("

"+sherpaLang["widget-selectshipping-title"]+"

"+sherpaLang["widget-selectshipping-desc"]+"

"+sherpaLang["widget-checkpostcode-title"]+"

"+sherpaLang["widget-checkpostcode-desc"]+"

"); $('.sherpa-wrapper').append(html); //default settings //pre-select sherpa option $('.sherpa-selectshipping').hide(); $(checkoutSelector).prop('disabled',true).addClass('disabled'); $('.sherpa-wrapper-calendar').hide(); $('.sherpa-wrapper-deliverynotes').hide(); $('.sherpa-checkpostcode').show(); shipWithSherpa = true; //add modal var modal = $("

"+sherpaLang['modal-title']+"

"+sherpaLang['modal-desc']+"

"); $('body').append(modal); if (allowPopupSkip) { $('.sherpa_btnRemoveItems').after("
"+sherpaLang['modal-skip-button']+"
"); $(document).on('click','.sherpa_btnSkip',function() { console.log('do skip'); removeCartToken($); $(checkoutSelector).prop('disabled',false).removeClass('disabled').trigger('click'); }); } $('body').click(function (event) { if(!$(event.target).closest('.sherpa-modal-content').length && !$(event.target).is('.sherpa-modal-content')) { $(".sherpa-modal-wrapper").hide(); } }); $(document).on('click','.sherpa-modal-close',function() { $(".sherpa-modal-wrapper").hide(); }); //setup shipping selections $(document).on('click','.sherpa_btnUseSherpa',function() { $(checkoutSelector).prop('disabled',true).addClass('disabled'); $('.sherpa-wrapper-calendar').hide(); $('.sherpa-wrapper-deliverynotes').hide(); $('.sherpa-checkpostcode').show(); $('.sherpa-checkpostcode .sherpa-header').hide(); shipWithSherpa = true; console.log('use sherpa shipping'); }); $(document).on('click','.sherpa_btnUseShipping',function() { $(checkoutSelector).prop('disabled',true).addClass('disabled'); $('.sherpa-wrapper-calendar').hide(); $('.sherpa-wrapper-deliverynotes').hide(); $('.sherpa-results').html(''); $('.sherpa-checkpostcode').hide(); shipWithSherpa = false; console.log('use normal shipping'); setTimeout(function() { removeCartToken($); showNextStep($,'LOCATION'); },100); }); //setup postcode checker $(document).on('keydown','.sherpa_txtPostcode',function(e) { clearTimeout(_postcodeAutoSubmitTimer); if (e.keyCode == 13) { e.preventDefault(); e.stopImmediatePropagation(); $('.sherpa_btnCheckPostcode').click(); return true; } var pc = $(this).val(); if (pc.length >= 3) { _postcodeAutoSubmitTimer = setTimeout(function() { console.log('do postcode check'); $('.sherpa_btnCheckPostcode').click(); },1000); } }); $(document).on('click','.sherpa_btnCheckPostcode',function() { var pc = $('.sherpa_txtPostcode').val(); if (pc.length < 3) { return false; } $(this).after('
Loading...
'); console.log('sherpa check postcode: '+pc); $(this).prop('disabled',true).addClass('disabled'); $(checkoutSelector).prop('disabled',true).addClass('disabled'); $('.sherpa-wrapper-calendar').hide(); $('.sherpa-wrapper-deliverynotes').hide(); $('.sherpa-results').html(''); checkoutItems = {}; //get current items var itemsPayload = {}; var itemsSerialised = []; $.ajax({ url: '/cart.js', type: 'GET', dataType: 'json', async: false, success: function(cart) { for (idx=0; idx < cart.items.length; idx++) { var item = cart.items[idx]; checkoutItems[item.variant_id] = {"key":item.key,"title":item.title,"qty":item.quantity,"vid":item.variant_id,"image":item.image}; if (typeof itemsPayload[item.variant_id] === 'undefined') itemsPayload[item.variant_id] = 0; itemsPayload[item.variant_id] += item.quantity; } } }); $.each(itemsPayload,function(vid,qty) { itemsSerialised.push(vid+'|'+qty); }); //do check $.ajax({ url: 'https://plugin-app.sherpa.net.au/api.php', type: 'POST', dataType: 'json', data: { 'a': 'checkLocation', 's': 'best-buds-admin.myshopify.com', 'p': pc, 'c': ' ', 'i': itemsSerialised.join(','), }, success: function(data) { //turn off calendar if (typeof data.forceCalendarOff !== 'undefined' && data.forceCalendarOff === true) { console.log('has sherpa-no-cal'); showCalendarWidget = false; } calendarAvailDOW = data.calendarAvailDOW; if (data.location === null) { console.log('location: none'); console.log('none fulfillable'); selectedLocation = null; $('.sherpa-results').html(sherpaLang["widget-none-fulfillable"]).removeClass('success').addClass('error'); //but allow checkout anyway removeCartToken($); showNextStep($,'SHOWEND'); } else if (data.unfulfillableItems.length == 0) { console.log('location: '+data.location[0]); console.log('all fulfillable'); if (data.hasActualRates) { //has valid rates as well console.log('has rates'); selectedLocation = data.location['id']; addCartToken($); showNextStep($,'LOCATION'); $('.sherpa-results').html(sherpaLang["widget-all-fulfillable"]).removeClass('error').addClass('success'); } else { console.log('no rates, likely out of range'); $('.sherpa-results').html(sherpaLang["widget-no-rates"]).removeClass('success').addClass('error'); //but allow checkout anyway removeCartToken($); showNextStep($,'SHOWEND'); } } else { console.log('location: '+data.location[0]); selectedLocation = data.location['id']; var numInStock = 0; if (typeof data.location['itemsInStock'] !== 'undefined') { numInStock = data.location['itemsInStock'].length; } else if (typeof data.location['itemsInStockOversell'] !== 'undefined') { numInStock = data.location['itemsInStockOversell'].length; } if (numInStock > 0) { console.log('some fulfillable'); //setup modal products $('.sherpa-modal-product-wrapper').html(''); itemsToRemove = []; $.each(data.unfulfillableItems,function(k,v) { $('.sherpa-modal-product-wrapper').append("

"+checkoutItems[v].title+"

"); itemsToRemove.push(v); }); $('.sherpa-modal-wrapper').show(); } else { console.log('none fulfillable'); $('.sherpa-results').html(sherpaLang["widget-none-fulfillable"]).removeClass('success').addClass('error'); //but allow checkout anyway removeCartToken($); showNextStep($,'SHOWEND'); } } $('#sherpa-datepicker').datepicker('option', 'minDate', new Date(data.calendarAvailMinTS*1000)); console.log('sherpa check complete'); $('.sherpa_btnCheckPostcode').prop('disabled',false).removeClass('disabled'); $('#postcodeSpinner').remove(); }, error: function() { $('.sherpa-results').html(sherpaLang["widget-invalid-postcode"]).removeClass('success').addClass('error'); $('.sherpa_btnCheckPostcode').prop('disabled',false).removeClass('disabled'); $('#postcodeSpinner').remove(); } }); }); //remove items $(document).on('click','.sherpa_btnRemoveItems',function() { console.log('sherpa removing items'); $(this).prop('disabled',true).addClass('disabled'); var updatePayload = {updates: {}}; $.each(itemsToRemove,function(k,vid) { console.log('removing vid: '+vid); updatePayload.updates[vid] = 0; //remove from cart (style 1) $('.cart__row').each(function() { if ($(this).html().indexOf(vid) > -1) { $(this).remove(); } }); //remove from cart (style 2) $('.cart-drawer__item').each(function() { if ($(this).html().indexOf(vid) > -1) { $(this).remove(); } }); //remove from cart (style 3) $('.cart-row').each(function() { if ($(this).html().indexOf(vid) > -1) { $(this).remove(); } }); }); console.log(updatePayload); $.ajax({ url: '/cart/sherpaupdate.js', type: 'POST', dataType: 'json', data: updatePayload, success: function(data) { console.log('remove complete'); addCartToken($); $(this).prop('disabled',false).removeClass('disabled'); showNextStep($,'LOCATION'); $('.sherpa-results').html(sherpaLang["widget-removed-offending"]).removeClass('error').addClass('success'); $(".sherpa-modal-wrapper").hide(); } }); }); } //end location checker widget //show calendar if (showCalendarWidget) { console.log('load calendar widget'); var cutoffTimeDOW = {"DEFAULT":{"mon":"1600","tue":"1600","wed":"1600","thu":"1600","fri":"1600","sat":false,"sun":false}}; var _readyTS = 1728652674; var html = $("
"); $('.sherpa-wrapper').append(html); var minDate = new Date(2024,9,11); var maxDate = new Date(2024,10,08); $('.sherpa_btnCalendar').on('click',function() { $('#sherpa-datepicker').datepicker('show'); }); $('#sherpa-datepicker').datepicker({ dateFormat: 'dd/mm/yy', minDate: minDate, maxDate: maxDate, beforeShowDay: function(date) { if (isDateValid($,date,cutoffTimeDOW,_readyTS)) { //allow return [true,"",""]; } else { //reject return [false,"date_not_available","Delivery not available"]; } }, onSelect: function(dateStr) { var _date = dateStr.split('/'); selectedDate = _date[2]+'-'+_date[1]+'-'+_date[0]; addCartToken($,true); showNextStep($,'CALENDAR'); } }); /* //select default date as first available date var defaultDate = new Date(); var foundDefaultDate = true; while (!isDateValid($,defaultDate,cutoffTimeDOW,_readyTS)) { defaultDate.setDate(defaultDate.getDate()+1); if (defaultDate.getTime() > maxDate.getTime()) { console.log('no default date found'); foundDefaultDate = false; break; } } if (foundDefaultDate) { selectedDate = getDateStr(defaultDate); var _selectedDate = selectedDate.split('-'); $('#sherpa-datepicker').val(_selectedDate[2]+'/'+_selectedDate[1]+'/'+_selectedDate[0]); addCartToken($,true); showNextStep($,'CALENDAR'); } */ if (!showLocationWidget) { $('.sherpa-wrapper-calendar').show(); $('.sherpa-wrapper-deliverynotes').hide(); } else { $('.sherpa-wrapper-calendar').hide(); $('.sherpa-wrapper-deliverynotes').hide(); } } //end calendar //add delivery instructions if (showDeliveryNotes) { var html = $("

"+sherpaLang['widget-delivery-notes-title']+"

"); $('.sherpa-wrapper').append(html); $(document).on('keydown','#sherpa-deliverynotes',function(e) { if (e.keyCode == 13) { e.preventDefault(); e.stopImmediatePropagation(); $(checkoutSelector).click(); return true; } }); } // //pre-select sherpa option // setTimeout(function() { // $('.sherpa_btnUseSherpa').click(); // },100); }; var sherpaOnCartChange = function($) { console.log('sherpa on cart change'); $('.sherpa-selectshipping').hide(); $('.sherpa-checkpostcode').show(); $(checkoutSelector).prop('disabled',true).addClass('disabled'); checkoutItems = {}; $('.sherpa-results').html(''); }; var addAjaxHooks = function($) { var oldOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function() { if (arguments[1].indexOf('sherpaupdate.js') > -1) { arguments[1] = arguments[1].replace('sherpaupdate.js','update.js'); } else if (arguments[1].indexOf('sherpachange.js') > -1) { arguments[1] = arguments[1].replace('sherpachange.js','change.js'); } else { if (arguments[1].indexOf('/cart/add.js')>-1 || arguments[1].indexOf('/cart/change.js')>-1 || arguments[1].indexOf('/cart/update.js')>-1) { console.log('sherpa attaching listener'); this.addEventListener('load', function() { sherpaOnCartChange($); }); } } oldOpen.apply(this, arguments); }; }; var runSherpa = function($) { console.log('sherpa init'); initUI($); }; var waitjQueryLoad = function(cb) { if (typeof window.jQuery != "undefined" && typeof window.jQuery.fx != "undefined") { var myJQ = window.jQuery.noConflict(); cb(myJQ); } else { //reschedule window.setTimeout(function() { waitjQueryLoad(cb); },100); } }; var waitjQueryUILoad = function($,cb) { if (typeof $.datepicker != "undefined") { cb($); } else { //reschedule window.setTimeout(function() { waitjQueryUILoad($,cb); },100); } }; var loadJQUI = function($) { if (typeof $.datepicker == "undefined") { console.log('sherpa load jQ UI'); var jqueryuisrc = document.createElement('script'); jqueryuisrc.type = 'text/javascript'; jqueryuisrc.src = '//code.jquery.com/ui/1.12.1/jquery-ui.min.js'; var oldjQuery = window.jQuery; window.jQuery = $; document.body.appendChild(jqueryuisrc); window.jQuery = oldjQuery; waitjQueryUILoad($,function(jq) { runSherpa(jq); }); } else { runSherpa($); } }; var jquery; if (window.jQuery) { jquery = window.jQuery.noConflict(); } else if (window.Checkout && window.Checkout.$) { jquery = window.Checkout.$.noConflict(); } if (typeof jquery == "undefined" || typeof jquery.fx == "undefined") { console.log('sherpa load jQ'); var jquerysrc = document.createElement('script'); jquerysrc.type = 'text/javascript'; jquerysrc.src = '//ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.1.min.js'; document.body.appendChild(jquerysrc); waitjQueryLoad(function(jq) { loadJQUI(jq); }); } else { loadJQUI(jquery); } })();