Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Fenix Global Calendar Script in the Shopify themes

...

...

  • Rename the duplicated theme as Fenix Integration-yourthemename for better visibility and avoid confusion for other developers. Refer to the below sample screenshot

...

  • Please use the above theme.

  • Search the Snippets keyword in the search and click on Add a new Snippet. Refer to the below sample screenshot.

  • Create two new snippets files named fenix-calendar.liquidandfenix-checkout-attributes.liquid.

...

  • Add below snippets into newly added fenix-calendar.liquid file

Code Block
<style>
   #fenix-checkout-calendar .fc-view-harness.fc-view-harness-active {
     height: 465px !important;
   }
   #fenix-checkout-calendar .fc-daygrid-body.fc-daygrid-body-unbalanced {
      width: 100% !important;
   }
   
   #fenix-checkout-calendar .fc-col-header {
      width: 100% !important;
   }
   .fenix-separator-month {
      width: 100px;
      text-align: left;
      margin: 8px 15px;
   }
  .fc .fc-scroller.fc-scroller-liquid-absolute {
    overflow-y: auto !important;
  }
  .fc .fc-daygrid-day-frame {
    position: relative;
    min-height: 77px;
    cursor: pointer;
}
  @media(max-width: 767px) {
    .section.section--shipping-method .section__header {
      padding: 25px 0;
    }
    .fc .fc-daygrid-day-frame {
        display: flex;
        flex-direction: column;
        justify-content: center;
     }
  }
</style>
   <script>
      const fastplane = `<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
      width="32.000000pt" height="32.000000pt" viewBox="0 0 32.000000 32.000000"
      preserveAspectRatio="xMidYMid meet">

      <g transform="translate(0.000000,32.000000) scale(0.100000,-0.100000)"
      fill="#000000" stroke="none">
      <path d="M236 281 l-38 -39 -79 26 c-73 24 -80 25 -95 10 -18 -18 -24 -12 75
      -73 l43 -27 -33 -34 c-22 -22 -41 -34 -55 -32 -12 2 -29 -4 -39 -12 -16 -13
      -15 -15 16 -25 24 -8 36 -20 44 -44 10 -31 12 -32 25 -16 8 10 14 27 12 39 -2
      14 10 33 32 55 l34 33 15 -23 c8 -13 27 -44 42 -68 25 -40 28 -42 43 -27 15
      15 14 22 -10 95 l-25 79 41 41 c34 34 39 44 30 59 -18 28 -37 25 -78 -17z"/>
      </g>
      </svg>`;


const freightplane = `<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
      width="32.000000pt" height="32.000000pt" viewBox="0 0 512.000000 512.000000"
      preserveAspectRatio="xMidYMid meet">

      <g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
      fill="#000000" stroke="none">
      <path d="M3909 4136 c-123 -50 -261 -160 -541 -427 -107 -103 -184 -169 -196
      -169 -11 0 -89 17 -173 39 -85 21 -166 41 -181 45 -66 15 -75 64 -23 126 19
      23 35 52 35 64 0 25 -108 136 -133 136 -8 0 -61 -51 -117 -112 -57 -62 -113
      -117 -124 -122 -15 -6 -91 10 -261 53 -258 67 -267 67 -301 16 -12 -19 -14
      -28 -5 -39 6 -7 212 -125 457 -262 253 -141 453 -259 461 -272 12 -17 13 -28
      5 -45 -5 -12 -79 -101 -162 -197 -84 -96 -218 -257 -299 -358 -84 -106 -155
      -185 -167 -188 -13 -3 -100 20 -206 55 -101 34 -195 61 -209 61 -29 0 -59 -28
      -59 -54 0 -11 52 -51 148 -113 219 -142 214 -135 156 -239 -19 -35 -33 -68
      -29 -74 4 -7 30 2 70 25 35 19 74 35 87 35 32 0 48 -19 160 -191 53 -81 101
      -150 107 -154 15 -9 58 19 65 43 4 11 -21 102 -59 213 -36 107 -64 205 -63
      219 2 17 29 45 88 93 197 159 397 325 520 432 72 63 139 115 149 115 10 0 28
      -8 39 -17 11 -10 131 -216 267 -458 136 -242 252 -446 257 -452 25 -31 88 10
      88 56 0 13 -28 132 -62 264 l-62 240 122 116 c67 64 122 122 122 129 0 23
      -111 132 -134 132 -13 0 -42 -21 -71 -50 -90 -91 -110 -72 -164 160 -23 96
      -41 188 -41 204 0 24 27 57 153 185 298 304 444 510 463 653 6 43 4 49 -24 77
      -38 38 -75 40 -153 7z"/>
      <path d="M1447 3062 c-229 -230 -417 -424 -417 -433 0 -28 30 -59 58 -59 22 0
      100 73 440 413 434 434 439 440 394 480 -10 10 -27 17 -38 17 -12 0 -174 -155
      -437 -418z"/>
      <path d="M1366 2011 c-219 -220 -247 -252 -241 -272 9 -30 32 -49 59 -49 29 0
      516 487 516 516 0 12 -8 28 -18 37 -42 39 -56 28 -316 -232z"/>
      <path d="M2982 1637 c-295 -296 -412 -419 -412 -435 0 -28 34 -62 62 -62 16 0
      138 115 435 413 434 433 439 439 397 481 -42 42 -48 37 -482 -397z"/>
      <path d="M1557 1702 c-203 -203 -307 -314 -307 -328 0 -27 19 -50 49 -59 21
      -6 59 29 337 306 214 214 314 320 314 335 0 11 -8 28 -18 37 -43 39 -53 31
      -375 -291z"/>
      <path d="M1758 1403 c-196 -197 -357 -365 -359 -373 -4 -40 19 -70 54 -70 30
      0 747 716 747 746 0 27 -30 54 -61 54 -18 0 -108 -84 -381 -357z"/>
      </g>
      </svg>
      `;

const truckdel = `<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
      width="32.000000pt" height="32.000000pt" viewBox="0 0 128.000000 128.000000"
      preserveAspectRatio="xMidYMid meet">

      <g transform="translate(0.000000,128.000000) scale(0.100000,-0.100000)"
      fill="#000000" stroke="none">
      <path d="M120 1060 c-8 -15 -6 -24 10 -40 19 -19 32 -20 340 -20 l320 0 0
      -148 c0 -102 4 -152 12 -160 8 -8 61 -12 174 -12 l163 0 30 -37 c30 -37 31
      -40 31 -140 l0 -103 -37 0 c-34 0 -41 5 -60 39 -30 52 -98 86 -155 78 -49 -7
      -85 -31 -117 -80 l-24 -37 -116 0 -116 1 -25 39 c-26 43 -88 80 -133 80 -56 0
      -128 -48 -148 -97 -7 -20 -16 -23 -64 -23 -66 0 -103 -26 -85 -60 9 -17 21
      -20 73 -20 61 0 62 -1 82 -37 32 -59 66 -78 140 -78 74 0 108 19 140 78 l20
      37 117 0 117 0 17 -35 c9 -20 30 -45 47 -57 40 -29 123 -36 165 -14 32 17 82
      74 82 94 0 8 23 12 68 12 40 0 73 5 80 12 8 8 12 57 12 153 l0 142 -42 59
      c-24 32 -72 115 -108 184 l-65 125 -97 3 c-91 3 -98 4 -98 23 0 11 -5 29 -10
      40 -10 18 -25 19 -370 19 -348 0 -360 -1 -370 -20z m933 -215 c20 -42 37 -78
      37 -80 0 -3 -49 -5 -110 -5 l-110 0 0 80 0 80 73 0 73 0 37 -75z m-581 -433
      c46 -47 11 -132 -56 -132 -59 0 -95 66 -65 121 21 41 86 46 121 11z m546 5
      c37 -30 31 -106 -8 -127 -53 -29 -120 8 -120 65 0 69 76 105 128 62z"/>
      <path d="M80 906 c-6 -8 -10 -25 -8 -38 l3 -23 194 -3 c201 -3 221 1 221 39 0
      33 -34 39 -218 39 -144 0 -182 -3 -192 -14z"/>
      <path d="M12 748 c-15 -15 -15 -41 0 -56 13 -13 361 -18 392 -6 19 7 21 45 4
      62 -17 17 -379 17 -396 0z"/>
      <path d="M82 588 c-6 -6 -12 -20 -12 -29 0 -33 25 -40 135 -37 90 3 110 6 119
      21 8 12 8 22 0 35 -9 14 -29 17 -120 20 -77 2 -113 -1 -122 -10z"/>
      </g>
      </svg>
      `;


let holidayslist = [];
let holidayslistdesc = [];
let alldates = [];
let allrates = [];
let allinputs = [];
let saturdayshipping = null;
let saturdayshippingtext = null;


let datepairrates = [];

let aAlldates = [];
let aAllrates = [];
let aAllinputs = [];
let aDatepairrates = [];
// create cookie function
function createCookie(name, value, days) {
   var date = new Date();
   days = days || 14; // 14 days
   path = '/';
   date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
   var expires = '; expires=' + date.toGMTString();
   var cookieValue = name + '=' + value + expires + '; path=' + path;
   cookieValue += '; domain=';
   document.cookie = cookieValue;
}

// read cookie function
function readCookie(name) {
   var allCookie = '' + document.cookie;
   var index = allCookie.indexOf(name);
   if (name === undefined || name === '' || index === -1) return '';
   var ind1 = allCookie.indexOf(';', index);
   if (ind1 == -1) ind1 = allCookie.length;
   return unescape(allCookie.substring(index + name.length + 1, ind1));
}


function returnShippingName() {
   let shippingname = "";
   $.each($(".content-box__row"), function(index, value) {
      if ($(value).find(".input-radio:checked").val() != undefined && $(value).find(".input-radio:checked").val() !== null) {
         shippingname = $(value).find(".radio__label__primary").attr("data-shipping-method-label-title");
      }
   });
   return shippingname;
}

function formatDate(date) {
   var d = new Date(date),
      month = '' + (d.getMonth() + 1),
      day = '' + d.getDate(),
      year = d.getFullYear();

   if (month.length < 2)
      month = '0' + month;
   if (day.length < 2)
      day = '0' + day;

   return [year, month, day].join('-');
}

function activateEddRow(dis, radioid) {
   $(".fc-day").removeClass("active");
   $(dis).addClass("active");
   if (radioid !== undefined && radioid !== "") {
      $("#" + radioid).trigger("click");
      $(".section__content").find(".content-box__row").hide();
      $("#" + radioid).parent().parent().parent().show();
      createCookie("fenix_delivery_date_checkout", $(dis).attr("data-date"), 1);
      createCookie("fenix_delivery_method_checkout", returnShippingName(), 1);

      $("input[name='checkout[attributes][FenixCommerce Delivery Date]']").val($(dis).attr("data-date"));
      $("input[name='checkout[attributes][FenixCommerce Shipping Method]']").val(returnShippingName());
   }
}


var holidays = {};
var ratescard = [];

function fenixCheckoutCalendar() {
   var url = "https://delest-v2.preprod.fenixcommerce.com/fenixdelest/api/v1/holidayinfo/getHolidayInfo";

   var xhr = new XMLHttpRequest();
   xhr.open("POST", url);

   xhr.setRequestHeader("accept", "application/json");
   xhr.setRequestHeader("Content-Type", "application/json");

   xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {

         holidays = JSON.parse(xhr.responseText)

         $.each(holidays.holidays, function(ii, holiday) {
            holidayslist.push(formatDate(holiday.date));
            holidayslistdesc.push(holiday.desc);
         });

         $.each($(".content-box__row"), function(index, value) {
            if ($(value).find(".small-text").text()) {
               let dateArray = $(value).find(".small-text").text().split(",");
               dateArray = dateArray[1].replace(")", "");
               // get current year 
               var currentyear = new Date();

               currentyear = currentyear.getFullYear();

               dateArray = new Date(dateArray + " " + currentyear);

               // dateArray = new Date(dateArray.getTime() + 330 * 60000);

               alldates.push(dateArray);

               let rate = $(value).find('.content-box__emphasis').text().trim();
               allrates.push(rate);
               allinputs.push($(value).find('input').attr('id'));

               // Saturday Shipping
               if ($(value).find(".radio__label").text().trim().toLowerCase().indexOf("saturday") > -1) {
                  saturdayshipping = rate;
                  saturdayshippingtext = $(value).find('input').attr('id');
               }

            }
         });

         $.each(alldates, function(ii, date) {
            datepairrates.push({
               'date': date,
               'rates': allrates[ii],
               'input': allinputs[ii]
            });
         });

         
         if (datepairrates.length == 0)
            return false;

         datepairrates.sort(function(a, b) {
            return new Date(b.date) - new Date(a.date);
         });
         
         for (var i = 0; i < datepairrates.length - 1; i++) {
            let first = datepairrates[i].date;
            let second = datepairrates[i + 1].date;

            let diff = first.getTime() - second.getTime();

            if (diff > 86400000) {
               for (var ii = 1; ii < (diff / 86400000); ii++) {
                  let day = new Date(datepairrates[i].date.getTime() - 86400000 * ii);
                  if (day.getDay() != 6) {
                     datepairrates.push({
                        'date': day,
                        'rates': datepairrates[i + 1].rates,
                        'input': datepairrates[i + 1].input
                     });
                  }
               }
            }
         }
         
         datepairrates.sort(function(a, b) {
            return new Date(b.date) - new Date(a.date);
         });

         var calendarEl = document.getElementById('fenix-checkout-calendar');

         var from_date = new Date();
         from_date.setDate(from_date.getDate() + 1);
         var datefirst = datepairrates[datepairrates.length - 1].date;
         var firstDay = new Date(datefirst.getFullYear(), datefirst.getMonth(), 1);
         var from_date_new = firstDay.setDate(firstDay.getDate());

         var month = datefirst.getMonth() + 1; // January
         var d = new Date(datefirst.getFullYear(), month + 1, 0);
         var last_date_new = d.setDate(d.getDate());


         var to_date = new Date();
         to_date.setDate(to_date.getDate() + 60);

         let toDate = new Date(datefirst);
         toDate.setDate(toDate.getDate() + 40);

         let smallestdate = new Date(datepairrates[datepairrates.length - 1].date);
         let leadTimeDays = 41 + Math.ceil(Math.abs(smallestdate - new Date()) / (1000 * 60 * 60 * 24));
         // calculate difference here for lead time days 
         //let leadtimedays = 41 + difference days // 2nd may = smallest date - todays date. and Days diff is lead time. 

         for (var i = 1; i < leadTimeDays; i++) {

            var eventdate = new Date();
            eventdate.setDate(eventdate.getDate() + i);
            let day = eventdate.getDay();
            let month = "";
            if (eventdate.getMonth() + 1 < 10) {
               month = "0" + (eventdate.getMonth() + 1);
            } else {
               month = eventdate.getMonth() + 1;
            }

            let dd = "";
            if (eventdate.getDate() < 10) {
               dd = "0" + (eventdate.getDate());
            } else {
               dd = eventdate.getDate();
            }
            
            let fulldate = eventdate.getFullYear() + "-" + month + "-" + dd;

            var d2 = new Date(fulldate);
            let d3 = new Date(fulldate+ " 00:00");
            var datefound = true;
            var price = allrates[0] + "|" + allinputs[0] + "| truckdel";
            // if saturday shipping day == 6
            if (d3.getDay() == 6 && saturdayshipping !== null) {
               price = saturdayshipping + "|" + saturdayshippingtext + "| fastplane";
            }

            for (let i = 0; i < datepairrates.length; i++) {
               var d1 = new Date(datepairrates[i].date);
               // resolved Saturday
               if (d1.getTime() >= d3.getTime() && d3.getDay() == 6 && saturdayshipping !== null) {
                  price = saturdayshipping + "|" + saturdayshippingtext + "| fastplane";
                  break;
               }
               
               if (d1.getTime() == d3.getTime()) {
                  if (i == 0) {
                     price = datepairrates[i].rates + "|" + datepairrates[i].input + "| truckdel";
                  } else {
                     price = datepairrates[i].rates + "|" + datepairrates[i].input + "| fastplane";
                  }
                  break;
               }
            }

            if (day !== 0 && $.inArray(fulldate, holidayslist) === -1 && d3.getTime() >= smallestdate.getTime()) {
               ratescard.push({
                  title: price,
                  start: fulldate,
                  constraint: 'businessHours',
                  html: true
               });
            } else if (day !== 0 && $.inArray(fulldate, holidayslist) !== -1 && d3.getTime() >= smallestdate.getTime()) {
               ratescard.push({
                  title: holidayslistdesc[holidayslist.indexOf(fulldate)] + "|disable",
                  start: fulldate,
                  constraint: 'businessHours',
                  html: true
               });
            }
         }
         
         function dateRangesss(startDate, endDate) {
            var start = startDate.split('-');
            var end = endDate.split('-');
            var startYear = parseInt(start[0]);
            var endYear = parseInt(end[0]);
            var dates = [];

            for (var i = startYear; i <= endYear; i++) {
               var endMonth = i != endYear ? 11 : parseInt(end[1]) - 1;
               var startMon = i === startYear ? parseInt(start[1]) - 1 : 0;
               for (var j = startMon; j <= endMonth; j = j > 12 ? j % 12 || 11 : j + 1) {
                  var month = j + 1;
                  var displayMonth = month < 10 ? '0' + month : month;
                  dates.push([i, displayMonth, '01'].join('-'));
               }
            }
            return dates;
         }
         let getAllMonths = dateRangesss(new Date(datefirst).toISOString().slice(0, 10), new Date(toDate).toISOString().slice(0, 10));
         
         var firstday = 0;
         var calendar = new FullCalendar.Calendar(calendarEl, {
            timeZone: 'local',
            firstDay: '0',
            headerToolbar: false,
            validRange: {
               start: new Date(datefirst),
               end: toDate
            },
            initialView: 'myView',
            views: {
               myView: {
                  type: "dayGridMonth",
                  duration: {
                     weeks: 6
                  } // for some reason { days: 30 } doesn't work
               }
            },

            initialDate: new Date(datefirst),
            navLinks: false, // can click day/week names to navigate views
            businessHours: [{
               daysOfWeek: [1, 2, 3, 4, 5, 6],
            }],
            editable: false,
            selectable: false,
            events: ratescard,
            showNonCurrentDates: false,
            eventDidMount: function(info) {
               let element = $(info.el);
               if (getAllMonths.indexOf(info.event.startStr) > -1) {
                  const separatorMonthName = new Date(info.event.start).toLocaleString('default', {
                     month: 'long'
                  });
                  const separator = `<div class="fenix-separator-month">${separatorMonthName}</div>`;
                  $(info.el).parents('td.fc-daygrid-day').parent('tr').before(separator);
               }
               let html = element.text();
               const htmlArray = html.split("|");
               let newhtml = "";

               let planeicon = "";
               let planeiconclass = "";
               if (htmlArray[2] !== undefined && htmlArray[2].trim() == "freightplane") {
                  planeicon = freightplane;
                  planeiconclass = "freightplane";
               } else if (htmlArray[2] !== undefined && htmlArray[2].trim() == "fastplane") {
                  planeicon = fastplane;
                  planeiconclass = "fastplane";
               } else if (htmlArray[2] !== undefined && htmlArray[2].trim() == "truckdel") {
                  planeicon = truckdel;
                  planeiconclass = "truckdel";
               }

               if (htmlArray[1] == "disable") {
                  newhtml = `<span class="holiday-desc fenix-icc" title="${htmlArray[0]}" alt="${htmlArray[0]}" inputid="${htmlArray[1]}">${htmlArray[0]}</span>`;
               } else {
                  newhtml = `<span class="fenix-icc" inputid="${htmlArray[1]}">${htmlArray[0]}</span><br><span class="${planeiconclass}">${planeicon}</span>`;
               }
               element.html(newhtml);

               if (firstday === 0 && htmlArray[1] != "disable") {
                  setTimeout(() => {
                     $("#" + htmlArray[1]).trigger("click");
                     $(".section__content").find(".content-box__row").hide();
                     $("#" + htmlArray[1]).parent().parent().parent().show();
                     $("#" + htmlArray[1]).addClass("active");
                     element.parent().parent().parent().parent().addClass("active");
                  }, 1000);
                  firstday++;
               }
               if (htmlArray[1] !== undefined && htmlArray[1] !== "" && htmlArray[1] != "disable") {
                  element.parent().parent().parent().parent().attr("onclick", `activateEddRow(this, "${htmlArray[1]}")`);
               }

               if (htmlArray[1] == "disable") {
                  element.parent().parent().parent().parent().addClass("disable-dates");
               }

            }
         });
         calendar.render();
      }
   };

   var data = '{"holidayPeriod": 40, "storeName": "kb-dev1.myshopify.com","tenantId": "08b7a83428f548fabd2d29804807da2b" }';

   xhr.send(data);

}

window.Checkout.jQuery(document).on('page:load', function() {
   if (Shopify.Checkout.step === "shipping_method") {

      const checkEleExists = setInterval(() => {
         if (jQuery('.section--shipping-method fieldset[data-shipping-methods] .content-box__row').length > 0) {
            fenixCheckoutCalendar();
            clearInterval(checkEleExists);
         }
      }, 40);

      $("#fenix-checkout-calendar").insertAfter("#main-header");
      setTimeout(() => {
         // update date for inputs
         if (ratescard !== undefined && ratescard.length > 0) {

            createCookie("fenix_delivery_date_checkout", ratescard[0].start, 1);
            createCookie("fenix_delivery_method_checkout", returnShippingName(), 1);

            $("input[name='checkout[attributes][FenixCommerce Delivery Date]']").val(readCookie("fenix_delivery_date_checkout"));
            $("input[name='checkout[attributes][FenixCommerce Shipping Method]']").val(returnShippingName());
         }
      }, 1000);
   }
});

 
</script>
  • Add the below snippets into fenix-checkout-attributes.liquid.

    • This code will show attribute notes in the backend while previewing the order.

...

Code Block
<div id="fenix-checkout-calendar"></div>
{% render "fenix-calendar" %}
{% render "fenix-checkout-attributes" %}
  • Copy and paste the above-provided code snippet completely into checkout.liquid file, and don't forget to click the Save button. Refer to the below sample screenshot.

...