berkmancenter/bookanook

View on GitHub
app/assets/javascripts/administrate/statistics.js

Summary

Maintainability
D
3 days
Test Coverage
/**
 *
 * Commons functions used for both statistics dashboard
 * and trigger rendering all types of charts
 *
 */

// Commmon preprocessing of data for column charts
// original intention was to use it for all charts
// but some heatmaps use CSV format
function commonPreprocess(model, data) {
  var processedData = [];
  var entityIds = Object.keys(data);

  for (var i = 0; i < entityIds.length; i++) {
    var reservations = data[entityIds[i]];
    var newReservations = [];

    for (var j = 0; j < reservations.length; j++) {
      newReservations.push({
        'id': reservations[j]['id'],
        'start_time': new Date(reservations[j]['start_time']),
        'end_time': new Date(reservations[j]['end_time'])
      });
    };
    processedData.push({
      'name': entitiyNames[entityIds[i]],
      'reservations': newReservations
    });
  };
  addEntitiesWithNoReservation(model, data, processedData);
  return processedData;
};

// Locations/nooks with no reservations are not included in the filter result
// because back-end APIs uses group_by clauses
// underlying functions add these entities with empty array values
function addEntitiesWithNoReservation(model, data, processedData) {
  var selectedEntities = $('.selectize-' + model).val();
  if(selectedEntities == '') {
    selectedEntities = $('.selectize-' + model).data('options').split(',');
  } else {
    selectedEntities = selectedEntities.split(',');
  }
  for (var i = 0; i < selectedEntities.length; i++) {
    if( !(selectedEntities[i] in data) ) {
      processedData.push({
        'id': selectedEntities[i],
        'name': entitiyNames[parseInt(selectedEntities[i])],
        'reservations': []
      });
    }
  }
};

// Name hash maps id of nook/location to its name
// e.g. 1: Grand Library
// filter results are grouped by ids.
// Names are used in the charts.
function buildEntitiesNameHash(model) {
  entitiyNames = {}
  if ($('.selectize-' + model).data('options')) {
    $('.selectize-' + model).data('options').split(',').forEach( function(tag) {
      var nook = tag.split(':');
      entitiyNames[nook[0]] = nook[1];
    });
  };
};

// Charts containers are originally hidden as they have borders
// show them when charts are initialized
function showChart($element) {
  $element.show();
}

$( function() {

  // Render charts on Nook-stats dashboard
  if ($('.nook-statistics').length) {
    buildEntitiesNameHash('nook');
    setSidebarLinkActive();
    $("#nooks-stats-filter").submit( function(e) {
      var url = $(this).attr('action');
      $.ajax({
        type: "POST",
        url: url,
        data: $(this).serialize(),
        dataType: "json",
        success: function(data) {
          $('.chart-wrapper').show();
          preprocessedData = commonPreprocess('nook', data['reservations_by_nook']);
          initializeColumnChart( $('#nooks-column-chart'), preprocessedData );
          initializeHoursColumnChart( $('#nooks-hours-column-chart'), preprocessedData );
          data_by_date = data['reservations_by_date'];
          initializeAllDaysHeatMap( $('#nooks-all-days-heatmap'), data_by_date );
          initializeDaysTimeHeatMap( $('#nooks-days-time-heatmap'), data_by_date );
          data_by_day = data['reservations_by_day'];
          $('#days-select')[0].selectedIndex = 0;
          $('#days-select').trigger('change');
        }
      });
      e.preventDefault(); // avoid to execute the actual submit of the form.
    });
  };

  // Render charts on Location-stats dashboard
  if ($('.location-statistics').length) {
    buildEntitiesNameHash('location');
    setSidebarLinkActive();
    $("#locations-stats-filter").submit( function(e) {
      var url = $(this).attr('action');
      $.ajax({
        type: "POST",
        url: url,
        data: $(this).serialize(),
        dataType: "json",
        success: function(data) {
          $('.chart-wrapper').show();
          preprocessedData = commonPreprocess('location', data['reservations_by_location']);
          initializeColumnChart( $('#locations-column-chart'), preprocessedData );
          initializeHoursColumnChart( $('#locations-hours-column-chart'), preprocessedData );
          data_by_date = data['reservations_by_date'];
          initializeAllDaysHeatMap( $('#locations-all-days-heatmap'), data_by_date );
          initializeDaysTimeHeatMap( $('#locations-days-time-heatmap'), data_by_date );
          data_by_day = data['reservations_by_day'];
          $('#days-select')[0].selectedIndex = 0;
          $('#days-select').trigger('change');
        }
      });
      e.preventDefault(); // avoid to execute the actual submit of the form.
    });

  };

  // On-click event function for downlaoding spreadsheet
  $('.download_spreadsheet').click( function(e) {
    $('#nooks_clone').val( $('#nooks').val() );
    $('#locations_clone').val( $('#locations').val() );
    $('#start_date_clone').val( $('#start_date_clone').val() );
    $('#end_date_clone').val( $('#end_date_clone').val() );
    $('.stats-download').submit();
    e.preventDefault();
  });

  // Nooks and Locations stats dashboards inherits from Reservations dashboard
  // on opening them reservations links get active.
  // This is used to set dasboards links to active
  function setSidebarLinkActive() {
    var sidebar_reservation_link = $('a[href="/admin/reservations"]');
    $(sidebar_reservation_link).removeClass('sidebar__link--active');
    $(sidebar_reservation_link).addClass('sidebar__link--inactive');
    var pagePath = window.location.pathname;
    $('a[href="' + pagePath + '"]').addClass('sidebar__link--active');
  }
});

// Reinitialize one_day_time_heatmap when another day is selected
// this can be moved to charts/one_day_time_heatmap.js
$('#days-select').change( function() {
  var selectedIndex = $(this)[0].selectedIndex;
  var selectedOption = $(this).find(":selected").text();
  initializeOneDayTimeHeatMap (
    $('.one-day-time-heatmap'),
    data_by_day,
    selectedIndex,
    selectedOption
  );

});

// Date util functions used by heatmaps
function dateToString(date) {
  return date.getFullYear() + '-' + (date.getMonth()  + 1) + '-' + date.getDate();
}

// Get the date selected in the filter
// if empty, get the smallest date in results
function getStartDate() {
  var selectedVal = $('#start_date').val();
  var date = new Date(selectedVal);
  if (selectedVal == '') {
    selectedVal = Object.keys(data_by_date).reduce(function (a, b) { return a < b ? a : b; });
    date = new Date(selectedVal);
    $('.start-date').val(date.toISOString().slice(0,10));
  }
  return date;
}

// Get the date selected in the filter
// if empty, get the largest date in results
function getEndDate() {
  var selectedVal = $('#end_date').val();
  var date = new Date(selectedVal);
  if (selectedVal == '') {
    date = new Date();
    $('.end-date').val(date.toISOString().slice(0,10));
  }
  return date;
}

// Used in heatmap charts to determine where to start y axis
function minDate() {
  var date = getStartDate();
  return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate());
}

// Used in heatmap charts to determine where to stop y aixs
function maxDate() {
  var date = getEndDate();
  return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate());
}