projects_service.js 4.21 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
import Vue from 'vue';
import VueResource from 'vue-resource';

import bp from '../../breakpoints';
import Api from '../../api';
import AccessorUtilities from '../../lib/utils/accessor';

import { FREQUENT_PROJECTS, HOUR_IN_MS, STORAGE_KEY } from '../constants';

Vue.use(VueResource);

export default class ProjectsService {
  constructor(currentUserName) {
    this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
    this.currentUserName = currentUserName;
    this.storageKey = `${this.currentUserName}/${STORAGE_KEY}`;
    this.projectsPath = Vue.resource(Api.buildUrl(Api.projectsPath));
  }

  getSearchedProjects(searchQuery) {
    return this.projectsPath.get({
      simple: false,
      per_page: 20,
      membership: !!gon.current_user_id,
      order_by: 'last_activity_at',
      search: searchQuery,
    });
  }

  getFrequentProjects() {
    if (this.isLocalStorageAvailable) {
      return this.getTopFrequentProjects();
    }
    return null;
  }

  logProjectAccess(project) {
    let matchFound = false;
    let storedFrequentProjects;

    if (this.isLocalStorageAvailable) {
      const storedRawProjects = localStorage.getItem(this.storageKey);

      // Check if there's any frequent projects list set
      if (!storedRawProjects) {
        // No frequent projects list set, set one up.
        storedFrequentProjects = [];
        storedFrequentProjects.push({ ...project, frequency: 1 });
      } else {
        // Check if project is already present in frequents list
        // When found, update metadata of it.
        storedFrequentProjects = JSON.parse(storedRawProjects).map((projectItem) => {
          if (projectItem.id === project.id) {
            matchFound = true;
            const diff = Math.abs(project.lastAccessedOn - projectItem.lastAccessedOn) / HOUR_IN_MS;
            const updatedProject = {
              ...project,
              frequency: projectItem.frequency,
              lastAccessedOn: projectItem.lastAccessedOn,
            };

            // Check if duration since last access of this project
            // is over an hour
            if (diff > 1) {
              return {
                ...updatedProject,
                frequency: updatedProject.frequency + 1,
                lastAccessedOn: Date.now(),
              };
            }

            return {
              ...updatedProject,
            };
          }

          return projectItem;
        });

        // Check whether currently logged project is present in frequents list
        if (!matchFound) {
          // We always keep size of frequents collection to 20 projects
          // out of which only 5 projects with
          // highest value of `frequency` and most recent `lastAccessedOn`
          // are shown in projects dropdown
          if (storedFrequentProjects.length === FREQUENT_PROJECTS.MAX_COUNT) {
            storedFrequentProjects.shift(); // Remove an item from head of array
          }

          storedFrequentProjects.push({ ...project, frequency: 1 });
        }
      }

      localStorage.setItem(this.storageKey, JSON.stringify(storedFrequentProjects));
    }
  }

  getTopFrequentProjects() {
    const storedFrequentProjects = JSON.parse(localStorage.getItem(this.storageKey));
    let frequentProjectsCount = FREQUENT_PROJECTS.LIST_COUNT_DESKTOP;

    if (!storedFrequentProjects) {
      return [];
    }

    if (bp.getBreakpointSize() === 'sm' ||
        bp.getBreakpointSize() === 'xs') {
      frequentProjectsCount = FREQUENT_PROJECTS.LIST_COUNT_MOBILE;
    }

    const frequentProjects = storedFrequentProjects
      .filter(project => project.frequency >= FREQUENT_PROJECTS.ELIGIBLE_FREQUENCY);

    // Sort all frequent projects in decending order of frequency
    // and then by lastAccessedOn with recent most first
    frequentProjects.sort((projectA, projectB) => {
      if (projectA.frequency < projectB.frequency) {
        return 1;
      } else if (projectA.frequency > projectB.frequency) {
        return -1;
      } else if (projectA.lastAccessedOn < projectB.lastAccessedOn) {
        return 1;
      } else if (projectA.lastAccessedOn > projectB.lastAccessedOn) {
        return -1;
      }

      return 0;
    });

    return _.first(frequentProjects, frequentProjectsCount);
  }
}