hummingbird-me/kitsu-web

View on GitHub
app/components/search-results.js

Summary

Maintainability
A
0 mins
Test Coverage
F
33%
import Component from '@ember/component';
import { get, set } from '@ember/object';
import { inject as service } from '@ember/service';
import { isEmpty } from '@ember/utils';
import { task, timeout } from 'ember-concurrency';
import { invokeAction } from 'ember-invoke-action';

const DEFAULT_INCLUDED = ['id', 'slug', 'kind'];
const INDICES = {
  media: [...DEFAULT_INCLUDED, 'canonicalTitle', 'titles', 'posterImage', 'subtype', 'posterImage'],
  users: [...DEFAULT_INCLUDED, 'name', 'avatar'],
  groups: [...DEFAULT_INCLUDED, 'name', 'avatar'],
};

const search = (indexName, attributesToRetrieve, hitsPerPage = 2) => (
  task(function* (query, options = {}) {
    const index = yield get(this, 'algolia.getIndex').perform(indexName);
    if (isEmpty(index)) {
      return {};
    }
    return yield index.search(query, {
      attributesToRetrieve,
      hitsPerPage,
      queryLanguages: ['en', 'ja'],
      naturalLanguages: ['en', 'ja'],
      attributesToHighlight: [],
      responseFields: ['hits', 'hitsPerPage', 'nbHits', 'nbPages', 'offset', 'page'],
      removeStopWords: false,
      removeWordsIfNoResults: 'allOptional',
      ...options
    });
  }).restartable()
);

export default Component.extend({
  isOpened: false,
  algolia: service(),
  metrics: service(),
  raven: service(),

  init() {
    this._super(...arguments);
    set(this, 'groups', { media: [], users: [], groups: [] });
  },

  didReceiveAttrs() {
    this._super(...arguments);
    const query = get(this, 'query');
    if (isEmpty(query) || get(this, 'queryWas') === query) {
      return;
    }
    set(this, 'queryWas', query);
    get(this, 'searchTask').perform(query).then(() => {
      get(this, 'metrics').trackEvent({ category: 'search', action: 'query', label: query });
    }).catch(error => {
      get(this, 'raven').captureException(error);
    });
  },

  searchTask: task(function* (query) {
    Object.keys(INDICES).forEach(type => {
      get(this, `${type}Task`).perform(query).then(response => {
        const records = get(response, 'hits') || [];
        set(this, `groups.${type}`, records);
        set(this, `groups.${type}.nbPages`, get(response, 'nbPages'));
      }).catch(error => {
        get(this, 'raven').captureException(error);
      });
    });
    yield timeout(250);
  }).keepLatest(),

  mediaTask: search('media', INDICES.media, 4),
  groupsTask: search('groups', INDICES.groups),
  usersTask: search('users', INDICES.users),

  nextPageTask: task(function* (kind, page) {
    const query = get(this, 'query');
    const response = yield get(this, `${kind}Task`).perform(query, { page });
    get(this, `groups.${kind}`).addObjects(get(response, 'hits'));
  }).drop(),

  actions: {
    close() {
      set(this, 'isOpened', false);
      invokeAction(this, 'onClose');
    }
  }
});