Vizzuality/gfw-climate

View on GitHub
app/assets/javascripts/data-download/views/DataDownloadIndexView.js

Summary

Maintainability
D
2 days
Test Coverage
define(
  [
    'backbone',
    'handlebars',
    'bluebird',
    'underscore',
    'jquery',
    'data-download/views/DownloadFilterCardView',
    'views/shared/SwitchView',
    'helpers/utilsHelper',
    'text!data-download/templates/download-filters.handlebars'
  ],
  function(
    Backbone,
    Handlebars,
    Promise,
    _,
    $,
    DownloadFilterCardView,
    SwitchView,
    UtilsHelper,
    tpl
  ) {
    'use strict';
    var DataDownloadIndexView = Backbone.View.extend({
      filters: [
        {
          id: 'country_codes',
          name: 'Countries'
        },
        {
          id: 'jurisdiction_ids',
          name: 'Jurisdictions',
          placeholder: 'Select a country'
        },
        {
          id: 'area_ids',
          name: 'Areas of interest',
          placeholder: 'Select a country'
        },
        {
          id: 'widget_ids',
          name: 'Indicators'
        },
        {
          id: 'dataSource',
          name: 'Data source',
          placeholder: 'Select an indicator',
          hide: true
        },
        {
          id: 'thresholds',
          name: '% Tree cover density',
          placeholder: 'Select an indicator'
        },
        {
          id: 'years',
          name: 'Years',
          placeholder: 'Select an indicator'
        }
      ],
      mandatorys: ['country_codes', 'widget_ids'],
      validationMsg:
        'Please select, at least, a country, an indicator and a year',
      tresh: [10, 15, 20, 25, 30],
      switchs: [
        {
          el: 'outputTypeSwitch',
          param: 'pivot',
          label: 'Output Type',
          options: [
            { label: 'Table', value: 0, selected: true },
            { label: 'Pivot', value: 1 }
          ]
        },
        {
          el: 'filerSwitch',
          param: 'json',
          label: 'File',
          options: [
            { label: '.csv', value: 0, selected: true },
            { label: '.json', value: 1 }
          ]
        }
      ],

      el: '#download-page',
      template: Handlebars.compile(tpl),

      events: {
        'click #download-btn': 'onDownloadClick',
        'click #clear-btn': 'onClearClick'
      },

      initialize: function() {
        this.filterViews = [];
        this.switchViews = [];
        this.filterIndex = {};
        this.availableIndicators = [];
        this.jurisdictionsData = {};
        this.domCache();
        this.getData().then(
          function() {
            this.populate();
            this.render();
          }.bind(this)
        );
      },

      domCache: function() {
        this.filtersContainer = this.$('#filters-container');
      },

      getData: function() {
        return Promise.all([
          $.getJSON('api/widgets'),
          $.getJSON('api/countries')
        ]).then(
          function(data) {
            this.widgets = data[0].widgets;
            this.countries = data[1].countries;
          }.bind(this)
        );
      },

      populate: function() {
        this.filters.forEach(function(filter) {
          switch (filter.id) {
            case 'country_codes':
              filter.options = this.getCountryOptions();
              break;
            case 'jurisdiction_ids':
              filter.options = [];
              break;
            case 'widget_ids':
              filter.options = this.getIndicatorsOptions();
              break;
            case 'dataSource':
              filter.options = [];
              break;
            case 'thresholds':
              filter.options = [];
              break;
            case 'years':
              filter.options = [];
              break;
            default:
              filter.options = [];
          }
        }, this);
      },

      getCountryOptions: function() {
        return this.countries.map(function(country) {
          return {
            value: country.iso,
            name: country.name
          };
        });
      },

      getCountryData: function(iso) {
        return $.getJSON('api/countries/' + iso).then(
          function(data) {
            if (data && data.country && data.country) {
              var parseData = function(items) {
                return items.map(function(item) {
                  return {
                    value: item.id,
                    name: item.name
                  };
                });
              };
              var jurisdictionsData = {
                areasOfInterest: parseData(data.country.areas_of_interest),
                jurisdictions: parseData(data.country.jurisdictions)
              };
              this.jurisdictionsData[iso] = jurisdictionsData;
              return jurisdictionsData;
            }
            return [];
          }.bind(this)
        );
      },

      getIndicatorsOptions: function() {
        return this.widgets.map(function(widget) {
          return {
            value: widget.id + '',
            indicators: widget.indicators.map(function(indicator) {
              return indicator.id;
            }),
            name: widget.name
          };
        });
      },

      setClearVisibility: function(value) {
        if (!this.clearBtn) {
          this.clearBtn = this.$('#clear-btn');
        }
        if (value) {
          this.clearBtn.removeClass('-hide');
        } else {
          this.clearBtn.addClass('-hide');
        }
      },

      onIndicatorsChange: function(selection) {
        var dataSourceOptions = [];
        this.availableIndicators = [];
        this.widgets.forEach(function(widget) {
          if (
            _.include(selection, widget.id + '') &&
            widget.tabs &&
            widget.tabs.length > 0
          ) {
            widget.tabs.forEach(function(tab) {
              this.availableIndicators.push(tab);
              dataSourceOptions.push({
                value: tab.name,
                name: tab.name
              });
            }, this);
          }
        }, this);

        this.filterViews[this.filterIndex.dataSource].renderOptions(
          dataSourceOptions,
          ''
        );
        if (dataSourceOptions) {
          this.filterViews[this.filterIndex.dataSource].setAllMarked(true);
          this.onDataSourceChange(
            dataSourceOptions.map(function(option) {
              return option.value;
            })
          );
        } else {
          this.filterViews[this.filterIndex.dataSource].setAllMarked(false);
        }
        this.setClearVisibility(true);
      },

      onDataSourceChange: function(selection) {
        var years = [];
        var trhesAllowed = false;

        if (selection && selection.length) {
          this.availableIndicators.forEach(function(indicator) {
            if (_.include(selection, indicator.name)) {
              if (indicator.range) {
                years = _.union(years, indicator.range);
              }
              if (indicator.thresh) {
                trhesAllowed = true;
              }
            }
          }, this);

          var yearsOptions = [];
          var yearsMsg = '';
          var selectAllYears = false;
          if (years.length) {
            yearsOptions = years.map(function(year) {
              return { name: year, value: year };
            });
            selectAllYears = true;
          } else {
            yearsMsg = 'No years availables';
          }
          this.filterViews[this.filterIndex.years].renderOptions(
            yearsOptions,
            yearsMsg
          );
          this.filterViews[this.filterIndex.years].setAllMarked(selectAllYears);

          if (trhesAllowed) {
            var trheshOptions = this.tresh.map(function(thresh) {
              return { name: thresh, value: thresh, selected: thresh === 30 };
            });
            this.filterViews[this.filterIndex.thresholds].renderOptions(
              trheshOptions
            );
          } else {
            this.filterViews[this.filterIndex.thresholds].renderOptions(
              [],
              'Threshold selection is not allowed'
            );
          }
        } else {
          this.filterViews[this.filterIndex.thresholds].renderOptions(
            [],
            'Select a data source'
          );
          this.filterViews[this.filterIndex.years].renderOptions(
            [],
            'Select a data source'
          );
          this.filterViews[this.filterIndex.years].setAllMarked(false);
        }
      },

      getTreeCoverOptions: function() {
        return this.tresh.map(function(tresh) {
          return {
            value: tresh,
            name: tresh + '%'
          };
        });
      },

      getYearsOptions: function() {
        return this.years.map(function(year) {
          return {
            value: year,
            name: year
          };
        });
      },

      render: function() {
        this.filtersContainer.html(this.template({ filters: this.filters }));
        this.filters.forEach(function(filter, index) {
          var view = new DownloadFilterCardView({
            el: '#' + filter.id + '-filter-card',
            filter: filter
          });
          this.listenTo(
            view,
            'option:changed',
            this.onOptionChange.bind(this, filter.id)
          );
          var filterindex = {};
          filterindex[filter.id] = index;
          this.filterIndex = _.extend(this.filterIndex, filterindex);
          this.filterViews.push(view);
        }, this);

        this.switchs.forEach(function(option) {
          var view = new SwitchView({
            el: '#' + option.el,
            param: option.param,
            data: {
              label: option.label,
              options: option.options
            }
          });
          this.switchViews.push(view);
        }, this);
      },

      checkDownloadAvailable: function() {
        var mandatorysSelected = 0;
        var hasSelected = function(view) {
          if (!view) return false;
          if (view.selection && view.selection.length > 0) return true;
          return false;
        };
        this.filterViews.forEach(function(view) {
          if (_.include(this.mandatorys, view.filter.id) && hasSelected(view)) {
            mandatorysSelected += 1;
          }
        }, this);
        var isValid = mandatorysSelected === this.mandatorys.length;
        this.$('#download-btn').prop('disabled', !isValid);
        if (!this.validationMsgEl) {
          this.validationMsgEl = this.$('.validation-msg');
        }
        if (isValid) {
          this.validationMsgEl.addClass('-hide');
        } else {
          this.validationMsgEl.removeClass('-hide');
        }
      },

      onOptionChange: function(type, selection) {
        switch (type) {
          case 'country_codes':
            this.onCountryChange(selection);
            break;
          case 'widget_ids':
            this.onIndicatorsChange(selection);
            break;
          case 'dataSource':
            this.onDataSourceChange(selection);
            break;

          default:
            break;
        }
        this.checkDownloadAvailable();
      },

      onCountryChange: function(selection) {
        var jurisIndex = this.filterIndex.jurisdiction_ids;
        var aoiIndex = this.filterIndex.area_ids;
        var jurisView = this.filterViews[jurisIndex];
        var aoiView = this.filterViews[aoiIndex];
        if (jurisView && aoiView) {
          if (selection && selection.length === 1) {
            var jurisdictions = [];
            var areasOfInterest = [];
            Promise.all(
              selection.map(
                function(country) {
                  if (!this.jurisdictionsData[country]) {
                    return this.getCountryData(country);
                  }
                  return this.jurisdictionsData[country];
                }.bind(this)
              )
            ).then(function(data) {
              if (data && data.length) {
                data.forEach(function(d) {
                  jurisdictions = d.jurisdictions.concat(jurisdictions);
                  areasOfInterest = d.areasOfInterest.concat(areasOfInterest);
                });
              }
              function sortByName(a, b) {
                if (a.name < b.name) return -1;
                if (a.name > b.name) return 1;
                return 0;
              }

              var populateOptions = function(options, view, emptyMsg) {
                var sortedOptions = options;
                var hasOptions = options.length > 0;
                if (hasOptions) {
                  sortedOptions = options.sort(sortByName);
                }
                var msg = hasOptions > 0 ? '' : emptyMsg;
                view.renderOptions(sortedOptions, msg);
              };
              populateOptions(
                jurisdictions,
                jurisView,
                'There is no jurisdictions'
              );
              populateOptions(
                areasOfInterest,
                aoiView,
                'There is no area of interest'
              );
            });
          } else if (selection && selection.length > 1) {
            jurisView.renderOptions([], 'Please select only one country');
            jurisView.setAllMarked(false);
            aoiView.renderOptions([], 'Please select only one country');
            aoiView.setAllMarked(false);
          } else {
            jurisView.renderOptions([]);
            jurisView.setAllMarked(false);
            aoiView.renderOptions([]);
            aoiView.setAllMarked(false);
          }
          this.setClearVisibility(true);
        }
      },

      onClearClick: function() {
        this.filterViews.forEach(function(view) {
          view.setAllMarked(false);
        });
        this.setClearVisibility(false);
      },

      onDownloadClick: function(e) {
        e.preventDefault();
        var downloadUrl = '/api/data_portal_downloads'; // TODO: move this to .env
        var query = '';
        var firstParam = true;
        this.filterViews.forEach(function(view, index) {
          if (view.selection.length > 0) {
            if ((index === 0 && firstParam) || query === '') {
              firstParam = false;
              query += '?';
            } else {
              query += '&';
            }
            var value = view.selection.join(',');
            query += view.filter.id + '[]=' + value;
          }
        });

        this.switchViews.forEach(function(view, index) {
          if (view.value === '1') {
            if ((index === 0 && firstParam) || query === '') {
              firstParam = false;
              query += '?';
            } else {
              query += '&';
            }
            query += view.param + '=' + view.value;
          }
        });

        window.open(downloadUrl + query, '_blank');
      }
    });

    return DataDownloadIndexView;
  }
);