ilios/frontend

View on GitHub
packages/ilios-common/addon/components/user-search.js

Summary

Maintainability
A
0 mins
Test Coverage
import { service } from '@ember/service';
import Component from '@glimmer/component';
import { cached, tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { restartableTask } from 'ember-concurrency';
import { TrackedAsyncData } from 'ember-async-data';

export default class UserSearch extends Component {
  @service store;
  @service intl;
  @tracked showMoreInputPrompt = false;
  @tracked searchReturned = false;
  @tracked userResults = [];
  @tracked instructorGroupResults = [];

  @cached
  get currentlyActiveInstructorGroupsData() {
    return new TrackedAsyncData(this.args.currentlyActiveInstructorGroups ?? []);
  }

  get currentlyActiveInstructorGroups() {
    if (!this.currentlyActiveInstructorGroupsData.isResolved) {
      return [];
    }

    return this.currentlyActiveInstructorGroupsData.value;
  }

  @cached
  get currentlyActiveUsersData() {
    return new TrackedAsyncData(this.args.currentlyActiveUsers ?? []);
  }

  get currentlyActiveUsers() {
    if (!this.currentlyActiveUsersData.isResolved) {
      return [];
    }

    return this.currentlyActiveUsersData.value;
  }

  get availableInstructorGroups() {
    return this.args.availableInstructorGroups || [];
  }

  get sortedResults() {
    const results = [...this.userResults, ...this.instructorGroupResults];
    const locale = this.intl.get('locale');
    results.sort((a, b) => {
      return a.sortTerm.localeCompare(b.sortTerm, locale, { numeric: true });
    });
    return results;
  }

  get roles() {
    return this.args.roles || '';
  }

  @action
  addUser(user) {
    if (this.args.addUser) {
      this.args.addUser(user);
    }
  }

  @action
  addInstructorGroup(group) {
    if (this.args.addInstructorGroup) {
      this.args.addInstructorGroup(group);
    }
  }

  search = restartableTask(async (searchTerms = '') => {
    this.showMoreInputPrompt = false;
    this.searchReturned = false;
    this.userResults = [];
    this.instructorGroupResults = [];
    const noWhiteSpaceTerm = searchTerms.replace(/ /g, '');
    if (noWhiteSpaceTerm.length === 0) {
      return;
    } else if (noWhiteSpaceTerm.length < 3) {
      this.showMoreInputPrompt = true;
      return;
    }
    this.userResults = await this.searchUsers(searchTerms);
    this.instructorGroupResults = this.searchInstructorGroups(searchTerms);
    this.searchReturned = true;
  });

  searchInstructorGroups(searchTerms) {
    const fragment = searchTerms.toLowerCase().trim();
    const filteredGroups = this.availableInstructorGroups.filter((group) => {
      return group.title?.toLowerCase().includes(fragment);
    });

    return filteredGroups.map((group) => {
      return { group, type: 'group', sortTerm: group.title };
    });
  }

  async searchUsers(searchTerms) {
    const query = {
      q: searchTerms,
      limit: 100,
    };
    if (this.roles) {
      query.filters = {
        roles: this.roles.split(','),
      };
    }
    const users = await this.store.query('user', query);
    return users.map((user) => {
      return { user, type: 'user', sortTerm: user.fullName };
    });
  }
}