Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
formControlName="project_name"
[data]="listProjects"
[searchKeyword]="keyword"
historyIdentifier="projectsSelected"
[historyIdentifier]="projectKeyForLocalStorage"
notFoundText="No projects found"
placeHolder="Enter the project name"
[itemTemplate]="itemTemplate"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { DATE_FORMAT, DATE_FORMAT_YEAR } from 'src/environments/environment';
import { TechnologiesComponent } from '../technologies/technologies.component';
import { MatDatepicker } from '@angular/material/datepicker';
import { Observable } from 'rxjs';
import { updateProjectStorage } from '../../utils/project-storage.util';
import { PROJECTS_KEY_FOR_LOCAL_STORAGE } from '../../../../../environments/environment';

type Merged = TechnologyState & ProjectState & ActivityState & EntryState;
@Component({
Expand All @@ -49,6 +51,7 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
activities$: Observable<Activity[]>;
goingToWorkOnThis = false;
shouldRestartEntry = false;
projectKeyForLocalStorage = PROJECTS_KEY_FOR_LOCAL_STORAGE;

constructor(
private formBuilder: FormBuilder,
Expand Down Expand Up @@ -81,6 +84,8 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
projectWithSearchField.search_field = `${project.customer.name} - ${project.name}`;
this.listProjects.push(projectWithSearchField);
});

updateProjectStorage(projects);
}
});

Expand Down
89 changes: 89 additions & 0 deletions src/app/modules/shared/utils/project-storage.util.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { updateProjectStorage, getProjectsOnStorage } from './project-storage.util';
import { Project } from '../models/project.model';
import { PROJECTS_KEY_FOR_LOCAL_STORAGE } from '../../../../environments/environment';

describe('Project Storage', () => {

let storageProjects: Project[];
let projectsIdentifier: string;
let serverProjects: Project[];
let testProject: Project;
let localStorageGetItemMock;

beforeEach(() => {
projectsIdentifier = PROJECTS_KEY_FOR_LOCAL_STORAGE;

testProject = {
customer: {
name: 'ioet Inc. (was E&Y)',
},
id: 'f3630e59-9408-497e-945b-848112bd5a44',
name: 'Time Tracker',
customer_id: '20c96c4d-5e26-4426-a704-8bdd98c83319',
status: 'active',
};

storageProjects = [
testProject
];

serverProjects = [
testProject,
{
customer: {
name: 'No Matter Name',
},
id: 'no-matter-id',
name: 'Warby Parker',
customer_id: 'no-matter-id',
status: 'active',
}
];

localStorageGetItemMock = spyOn(localStorage, 'getItem').and.returnValue(JSON.stringify(storageProjects));
spyOn(localStorage, 'setItem');

});

it('If exists projects in localStorage and the server returns the same project, should keep the same localStorage variables', () => {
updateProjectStorage(serverProjects);

expect(localStorage.setItem).toHaveBeenCalledWith(projectsIdentifier, JSON.stringify(storageProjects));
});

it('If exists projects in localStorage and the server does not return that project, should update the localStorage variable', () => {
serverProjects.shift();

updateProjectStorage(serverProjects);

expect(localStorage.setItem).toHaveBeenCalledWith(projectsIdentifier, JSON.stringify([]));
});

it('If Server projects is empty, should not update the localStorage', () => {
serverProjects = [];

updateProjectStorage(serverProjects);

expect(localStorage.setItem).toHaveBeenCalledTimes(0);
});

it('If variables does not exists on localStorage, getProjectsOnStorage should return undefined', () => {
projectsIdentifier = 'no-matter-identifier';

localStorageGetItemMock.and.returnValue(undefined);

const projects = getProjectsOnStorage(projectsIdentifier);

expect(projects).toBeUndefined();
});

it('If variables not exists on localStorage, getProjectsOnStorage should return an array of Projects', () => {
const storageProjectsString = JSON.stringify(storageProjects);
localStorageGetItemMock.and.returnValue(storageProjectsString);

const projects = getProjectsOnStorage(projectsIdentifier);

expect(projects).toEqual(JSON.parse(storageProjectsString));
});
});

29 changes: 29 additions & 0 deletions src/app/modules/shared/utils/project-storage.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Project } from '../models/project.model';
import { PROJECTS_KEY_FOR_LOCAL_STORAGE as projectsKey } from '../../../../environments/environment';
import { isEmpty } from 'lodash';

export function updateProjectStorage(serverProjects: Project[]): void {
const storageProjects: Project[] = getProjectsOnStorage(projectsKey);
const isServerProjectsEmpty = isEmpty(serverProjects);
const updatedStorageProjects: Project[] = [];

if (!isServerProjectsEmpty && storageProjects) {
storageProjects.forEach((storageProject: Project) => {
const project = serverProjects.find((serverProject) => serverProject.id === storageProject.id);

if (project) {
updatedStorageProjects.push(project);
}
});

const projectsForLocalStorage = JSON.stringify(updatedStorageProjects);
localStorage.setItem(projectsKey, projectsForLocalStorage);
}
}

export function getProjectsOnStorage(projectsIdentifier: string): Project[] {
const projectsInsideLocalStorage: string = localStorage.getItem(projectsIdentifier);
return projectsInsideLocalStorage && JSON.parse(projectsInsideLocalStorage);
}


Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[data]="listProjects"
[searchKeyword]="keyword"
[initialValue]=""
historyIdentifier="projectsSelected"
[historyIdentifier]="projectKeyForLocalStorage"
notFoundText="No projects found"
placeHolder="Enter the project name"
[itemTemplate]="itemTemplate"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { Activity, } from '../../../shared/models';
import { LoadActivities } from './../../../activities-management/store/activity-management.actions';
import { allActivities } from 'src/app/modules/activities-management/store/activity-management.selectors';
import { head } from 'lodash';
import { updateProjectStorage } from '../../../shared/utils/project-storage.util';
import { PROJECTS_KEY_FOR_LOCAL_STORAGE } from '../../../../../environments/environment';

@Component({
selector: 'app-project-list-hover',
Expand All @@ -36,6 +38,7 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy {
projectsSubscription: Subscription;
activeEntrySubscription: Subscription;
loadActivitiesSubscription: Subscription;
projectKeyForLocalStorage = PROJECTS_KEY_FOR_LOCAL_STORAGE;

constructor(
private formBuilder: FormBuilder,
Expand All @@ -57,6 +60,8 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy {
projectWithSearchField.search_field = `${project.customer.name} - ${project.name}`;
this.listProjects.push(projectWithSearchField);
});

updateProjectStorage(projects);
this.loadActiveTimeEntry();
});
this.store.dispatch(new LoadActivities());
Expand Down
8 changes: 8 additions & 0 deletions src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ export const ROLES = {
value: 'time-tracker-tester',
},
};

/*
This variable is used by the ng-autocomplete component used in these files:
- details-fielfs.component.ts
- project-list-hover.component.ts
The purpose is to store the latest projects in the Local Storage with the next key.
*/
export const PROJECTS_KEY_FOR_LOCAL_STORAGE = 'projectsSelected';
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
Expand Down