presidential-innovation-fellows/code-gov-web

View on GitHub
src/app/components/base-filter-page/base-filter-page.component.ts

Summary

Maintainability
D
2 days
Test Coverage
import { JsonPipe } from '@angular/common';
import { ChangeDetectorRef, Component, ElementRef, ViewEncapsulation } from '@angular/core';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/map';
import * as licenseList from 'spdx-license-list';
import { ClientService } from '../../services/client';
import { StateService } from '../../services/state';
import * as allLanguages from '../../../enums/languages.json';

import { content, images } from '../../../../config/code-gov-config.json';

const licenseNameToId = {};
const licenseIdToName = {};
Object.entries(licenseList).forEach(values => {
  const [licenseId, licenseData] = values;
  const licenseName = licenseData.name;
  licenseNameToId[licenseName] = licenseId;
  licenseIdToName[licenseId] = licenseName;
});


@Component({
  selector: 'base-filter-page',
  styles: [require('./base-filter-page.styles.scss')],
  template: ''
})

export class BaseFilterPageComponent {
  public searchQuery: string = '';
  public bannerImage: SafeStyle;
  public queryValue: string = '';
  public routeSubscription: Subscription;
  public results = [];
  public finalResults = [];
  public total: number;
  public isLoading = true;
  public pageSize = 10;
  public agencies = [];
  public licenses = [];
  public languages = [];
  public hostElement: ElementRef;
  public filterTags = [];
  public types = [];

  // added by children
  public sortOptions: String[];
  public selectedSortOption: String;

  /**
   * On removal from the DOM, unsubscribe from URL updates.
   */
  public ngOnDestroy() {
    if (this.routeSubscription) {
      this.routeSubscription.unsubscribe();
    }
  }

  public getFilterBoxValues(title) {
    try {
      const element = this.hostElement.nativeElement.querySelector(`filter-box[title='${title}']`);
      if (element) {
        return element.values;
      } else {
        return [];
      }
    } catch (error) {
      console.warn(`getFilterBoxValues caught the following error with ${title}`, error);
      return [];
    }
  }

  public filterUsageType(result) {
    const selectedUsageTypes = this.getFilterBoxValues('Usage Type');

    if (selectedUsageTypes.length === 0) {
      return true;
    } else {
      return selectedUsageTypes.indexOf(result.permissions.usageType) > -1;
    }
  }

  public filterType(result) {
    const selectedTypes = this.getFilterBoxValues('Type');

    if (selectedTypes.length === 0) {
      return true;
    } else {
      return selectedTypes.indexOf(result.type) > -1;
    }
  }

  public filterOrgType(result) {
    const orgTypes = this.getFilterBoxValues('Organization Type');
    if (orgTypes.length === 0) {
      return true;
    } else {
      return orgTypes.indexOf(result.orgType || 'federal') > -1;
    }
  }

  public filterFederalAgency(result) {
    const names = this.getFilterBoxValues('Federal Agency');
    if (names.length === 0) {
      return true;
    } else if (names.length > 0) {
      return names.indexOf(result.agency.acronym) > -1;
    }
  }

  public filterSkillLevel(result) {
    const names = this.getFilterBoxValues('Skill Level');
    if (names.length === 0) {
      return true;
    } else if (names.length > 0) {
      return names.indexOf(result.skill) > -1;
    }
  }

  public filterTimeRequired(result) {
    const names = this.getFilterBoxValues('Time Required');
    if (names.length === 0) {
      return true;
    } else if (names.length > 0) {
      return names.indexOf(result.effort) > -1;
    }
  }

  public filterLanguages(result) {
    const selectedLangs = this.getFilterBoxValues('Language');

    if (selectedLangs.length === 0) {
      return true;
    } else if (selectedLangs.length > 0) {
      const repoLanguages = result.languages;
      if (Array.isArray(repoLanguages)) {
        return repoLanguages.some(repoLang => selectedLangs.indexOf(repoLang) > -1);
      }
    }
  }

  public filterLicenses(result) {
    const selectedLicenseIds = this.getFilterBoxValues('License');
    const selectedLicenseNames = selectedLicenseIds.map(id => licenseIdToName[id]);
    let selectedLicenses = Array.from(new Set(selectedLicenseIds.concat(selectedLicenseNames)));

    if (selectedLicenseIds.length === 0) {
      return true;
    } else if (selectedLicenseIds.length > 0) {
      if (Array.isArray(result.permissions.licenses)) {
        const objLicenseNames = result.permissions.licenses.map(license => license.name);
        return selectedLicenses.some(l => objLicenseNames.indexOf(l) > -1);
      } else {
        return false;
      }
    } else {
      return false;
    }
  }

  public filterResults() {
    this.finalResults = this.results
      .filter(this.filterLanguages.bind(this))
      .filter(this.filterLicenses.bind(this))
      .filter(this.filterUsageType.bind(this))
    //  .filter(this.filterOrgType.bind(this))
      .filter(this.filterType.bind(this))
      .filter(this.filterSkillLevel.bind(this))
      .filter(this.filterTimeRequired.bind(this))
      .filter(this.filterFederalAgency.bind(this));
  }

  public setLanguages() {
    let languages = new Set();
    this.results.forEach(result => {
      if (Array.isArray(result.languages)) {
        result.languages.forEach(language => {
          if (allLanguages.indexOf(language) > -1) {
            languages.add(language);
          }
        });
      }
    });
    this.languages = Array.from(languages).sort();
  }

  public setFederalAgencies(initialAgencies = []) {
    const nameToAcronym = {};
    const names = new Set();
    this.results.forEach(repo => {
      const agency = repo.agency;
      nameToAcronym[agency.name] = agency.acronym;
      names.add(agency.name);
    });
    this.agencies = Array.from(names).sort().map(name => {
      const acronym = nameToAcronym[name];
      const checked = typeof initialAgencies === 'object' && initialAgencies.indexOf(acronym) > -1;
      return { name: name, value: acronym, checked: checked };
    });
  }

  public setLicenses() {
    let licenses = new Set();
    this.results.forEach(result => {
      if (result.permissions && result.permissions.licenses) {
        result.permissions.licenses.forEach(license => {
          if (license.name) {
            const licenseName = license.name;
            if (licenseNameToId.hasOwnProperty(licenseName)) {
              licenses.add(JSON.stringify({ name: licenseName, value: licenseNameToId[licenseName] }));
            } else if (licenseIdToName.hasOwnProperty(licenseName)) {
              licenses.add(JSON.stringify({ name: licenseIdToName[licenseName], value: licenseName }));
            }
          }
        });
      }
    });
    this.licenses = Array.from(licenses)
      .map(license => JSON.parse(license))
      .sort((a, b) => a.name < b.name ? -1 : 1);
  }

  public setTypes() {
    let types = new Set();
    this.results.forEach(result => {
      if (result.type) {
        types.add(result.type);
      }
    });
    this.types = Array.from(types).sort();
  }

  public onFilterBoxChange(event) {
    this.filterResults();

    const target = event.target;
    if (target.tagName === 'INPUT') {
      const li = target.parentElement;
      const ul = li.parentElement;
      const container = ul.parentElement;
      const webComponent = container.parentElement;

      const category = webComponent.title;
      const checked = target.checked;
      const value = target.value;
      const name = li.querySelector('label').textContent;

      if (checked) {
        this.filterTags.push({ category, name, value });
      } else {
        this.filterTags = this.filterTags.filter(tag => {
          return tag.category !== category && tag.name !== name;
        });
      }
    }

    // set federal agency params
    // const names = this.getFilterBoxValues('Federal Agency');
    // let hash = window.location.hash.replace(/\?agencies=[^&]*/, '');
    // if (names.length === 0) {
    //  window.location.hash = hash;
    // } else {
    //  window.location.hash = hash + '?agencies=' + names.join(',');
    // }
  }

  /* on trigger by click on filter tag */
  public removeFilterTag(target) {
    this.filterTags = this.filterTags.filter(tag => tag !== target);
    const nativeElement = this.hostElement.nativeElement;
    const selector = `filter-box[title='${target.category}'] input[value='${target.value}']`;
    nativeElement.querySelector(selector).checked = false;
    this.filterResults();
  }

  public onSortSelectionChange() {
    this.sortResults();
  }

  public sortResults() {
    switch (this.selectedSortOption) {
      case 'A-Z':
        this.finalResults.sort((a, b) => a.name.trim() < b.name.trim() ? -1 : 1);
        break;
      case 'Best Match':
        this.finalResults.sort((a, b) => {
          if (a.searchScore < b.searchScore) {
            return 1;
          } else if (a.searchScore > b.searchScore) {
            return -1;
          } else {
            // sort by name
            return a.name.trim() < b.name.trim() ? -1 : 1;
          }
        });
        break;
      case 'Data Quality':
        this.finalResults.sort((a, b) => {
          if (a.score < b.score) {
            return 1;
          } else if (a.score > b.score) {
            return -1;
          } else {
            // sort by name
            return a.name.trim() < b.name.trim() ? -1 : 1;
          }
        });
        break;
      case 'Last Updated':
        this.finalResults.sort((a, b) => {
          const aTime = a.date && a.date.lastModified ? new Date(a.date.lastModified).getTime() :  -10e10;
          const bTime = b.date && b.date.lastModified ? new Date(b.date.lastModified).getTime() :  -10e10;
          return Math.sign(bTime - aTime) || 0;
        });
        break;
      default:
        break;
    }
  }
}