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
3 changes: 2 additions & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
],
"styles": [
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.scss"
"src/styles.scss",
"node_modules/ngx-toastr/toastr.css"
],
"scripts": [
"./node_modules/jquery/dist/jquery.min.js",
Expand Down
11 changes: 8 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"private": true,
"dependencies": {
"@angular/animations": "~9.0.3",
"@angular/animations": "^9.0.7",
"@angular/common": "~9.0.3",
"@angular/compiler": "~9.0.3",
"@angular/core": "~9.0.3",
Expand All @@ -29,6 +29,7 @@
"minimist": "^1.2.5",
"msal": "^1.2.1",
"ngx-pagination": "^5.0.0",
"ngx-toastr": "^12.0.1",
"rxjs": "~6.5.4",
"tslib": "^1.10.0",
"zone.js": "~0.10.2"
Expand Down
1 change: 1 addition & 0 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ import { Component } from '@angular/core';
})
export class AppComponent {
title = 'time-tracker';

}
6 changes: 4 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ToastrModule } from 'ngx-toastr';
import { CommonModule } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
Expand Down Expand Up @@ -54,7 +56,6 @@ import { CreateProjectTypeComponent } from './modules/customer-management/compon
import { CustomerEffects } from './modules/customer-management/store/customer-management.effects';
import { EntryEffects } from './modules/time-clock/store/entry.effects';
import { InjectTokenInterceptor } from './modules/shared/interceptors/inject.token.interceptor';
import { NotificationComponent } from './modules/shared/components/notification/notification/notification.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -89,11 +90,11 @@ import { NotificationComponent } from './modules/shared/components/notification/
ProjectTypeListComponent,
CreateProjectTypeComponent,
EntryFieldsComponent,
NotificationComponent,
],
imports: [
CommonModule,
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
Expand All @@ -116,6 +117,7 @@ import { NotificationComponent } from './modules/shared/components/notification/
ProjectTypeEffects,
EntryEffects,
]),
ToastrModule.forRoot()
],
providers: [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<div class="container">
<app-notification [notificationMsg]="notificationMsg" [isError]="isError" *ngIf="showNotification"></app-notification>
<div class="row">
<div class="col">
<app-create-activity></app-create-activity>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,37 @@ import { ActivityService } from './../services/activity.service';
import { ActivitiesManagementComponent } from './activities-management.component';
import { ActionsSubject } from '@ngrx/store';
import { ActivityManagementActionTypes } from '../store';
import { ToastrService, ToastrModule, IndividualConfig } from 'ngx-toastr';

describe('ActivitiesManagementComponent', () => {
let component: ActivitiesManagementComponent;
let fixture: ComponentFixture<ActivitiesManagementComponent>;
let activityService: ActivityService;
const activitiesFromApi: Activity[] = [{ id: '123', name: 'aaa', description: 'xxx' }];
const toastrService = {
success: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { },
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { }
};
let injectedToastrService;

beforeEach(async(() => {
const actionSub: ActionsSubject = new ActionsSubject();
TestBed.configureTestingModule({
imports: [ToastrModule.forRoot()],
declarations: [ActivitiesManagementComponent],
providers: [ActivityService, HttpClient, HttpHandler, { provide: ActionsSubject, useValue: actionSub }],
providers: [ActivityService, HttpClient, HttpHandler,
{ provide: ActionsSubject, useValue: actionSub },
{ provide: ToastrService, useValue: toastrService }
],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(ActivitiesManagementComponent);
component = fixture.componentInstance;
fixture.detectChanges();

injectedToastrService = TestBed.inject(ToastrService);
console.log(injectedToastrService);
activityService = TestBed.inject(ActivityService);
spyOn(activityService, 'getActivities').and.returnValue(of(activitiesFromApi));
});
Expand All @@ -47,9 +58,17 @@ describe('ActivitiesManagementComponent', () => {
});

it('has a succesfull message on CREATE_ACTIVITY_SUCCESS', () => {
spyOn(injectedToastrService, 'success');
component.setDataNotification(ActivityManagementActionTypes.CREATE_ACTIVITY_SUCCESS);

expect(component.notificationMsg).toBe('The activity has been saved successfully.');
expect(injectedToastrService.success).toHaveBeenCalled();
});

it('has a succesfull message on UPDATE_ACTIVITY_SUCCESS', () => {
spyOn(injectedToastrService, 'success');
component.setDataNotification(ActivityManagementActionTypes.UPDATE_ACTIVITY_SUCCESS);

expect(injectedToastrService.success).toHaveBeenCalled();
});

it('should destroy the subscription', () => {
Expand All @@ -62,38 +81,49 @@ describe('ActivitiesManagementComponent', () => {
});

it('#setDataNotification should show an success notification with DELETE_ACTIVITY_SUCCESS case', () => {
spyOn(injectedToastrService, 'success').and.returnValue(of(activitiesFromApi));
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
const action = {
type: '[ActivityManagement] DELETE_ACTIVITY_SUCESS',
};
actionSubject.next(action);

component.setDataNotification(action.type);
expect(component.showNotification).toBeTrue();
expect(component.isError).toBeFalse();
expect(injectedToastrService.success).toHaveBeenCalled();
});

it('#setDataNotification should show an error notification with CREATE_ACTIVITY_FAIL case', () => {
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
const action = {
type: '[ActivityManagement] CREATE_ACTIVITY_FAIL',
};
actionSubject.next(action);
it('shows an error notification with CREATE_ACTIVITY_FAIL case', () => {
spyOn(injectedToastrService, 'error');

component.setDataNotification(action.type);
expect(component.showNotification).toBeTrue();
expect(component.isError).toBeTrue();
component.setDataNotification(ActivityManagementActionTypes.CREATE_ACTIVITY_FAIL);

expect(injectedToastrService.error).toHaveBeenCalled();
});

it('shows an error notification with UPDATE_ACTIVITY_FAIL case', () => {
spyOn(injectedToastrService, 'error');

component.setDataNotification(ActivityManagementActionTypes.UPDATE_ACTIVITY_FAIL);

expect(injectedToastrService.error).toHaveBeenCalled();
});

it('shows an error notification with DELETE_ACTIVITY_FAIL case', () => {
spyOn(injectedToastrService, 'error');

component.setDataNotification(ActivityManagementActionTypes.DELETE_ACTIVITY_FAIL);

expect(injectedToastrService.error).toHaveBeenCalled();
});

it('#setDataNotification should not show an error notification with incorrect action', () => {
spyOn(injectedToastrService, 'success').and.returnValue(of(activitiesFromApi));
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
const action = {
type: '[ActivityManagement] TEST',
};
actionSubject.next(action);

component.setDataNotification(action.type);
expect(component.showNotification).toBeFalse();
expect(component.isError).toBeFalse();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@ import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActionsSubject } from '@ngrx/store';
import { Subscription } from 'rxjs';
import { ActivityManagementActionTypes } from '../store';
import { ToastrService } from 'ngx-toastr';

@Component({
selector: 'app-activities-management',
templateUrl: './activities-management.component.html',
styleUrls: ['./activities-management.component.scss'],
})
export class ActivitiesManagementComponent implements OnInit, OnDestroy {
notificationMsg = '';
showNotification = false;
isError = false;
actionsSubscription: Subscription;

constructor(private actionsSubject$: ActionsSubject) {}
constructor(private actionsSubject$: ActionsSubject, private toastrService: ToastrService) {}

ngOnInit() {
this.actionsSubscription = this.actionsSubject$.subscribe((action) => {
Expand All @@ -27,26 +25,31 @@ export class ActivitiesManagementComponent implements OnInit, OnDestroy {
}

setDataNotification(action: any) {
this.showNotification = true;
switch (action) {
case ActivityManagementActionTypes.CREATE_ACTIVITY_SUCCESS: {
this.notificationMsg = 'The activity has been saved successfully.';
this.toastrService.success('The activity has been saved successfully.');
break;
}
case ActivityManagementActionTypes.UPDATE_ACTIVITY_SUCCESS: {
this.toastrService.success('The activity has been saved successfully.');
break;
}
case ActivityManagementActionTypes.DELETE_ACTIVITY_SUCCESS: {
this.notificationMsg = 'The activity has been removed successfully.';
this.toastrService.success('The activity has been removed successfully.');
break;
}
case ActivityManagementActionTypes.CREATE_ACTIVITY_FAIL: {
this.toastrService.error('An unexpected error happened, please try again later.');
break;
}
case ActivityManagementActionTypes.CREATE_ACTIVITY_FAIL || ActivityManagementActionTypes.DELETE_ACTIVITY_FAIL: {
this.notificationMsg = 'An unexpected error happened, please try again later.';
this.isError = true;
case ActivityManagementActionTypes.UPDATE_ACTIVITY_FAIL: {
this.toastrService.error('An unexpected error happened, please try again later.');
break;
}
default: {
this.showNotification = false;
case ActivityManagementActionTypes.DELETE_ACTIVITY_FAIL : {
this.toastrService.error('An unexpected error happened, please try again later.');
break;
}
}
setTimeout(() => ((this.showNotification = false), (this.isError = false)), 3000);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
<div class="container">
<form style="width: 600px;" [formGroup]="customerForm" (ngSubmit)="onSubmit(customerForm.value)">
<div class="form-group">
<div
*ngIf="showAlert && messageToShow !== ''"
[ngClass]="{'bg-secondary': messageToShow == 'Customer created successfully!' || messageToShow == 'Customer updated successfully!',
'bg-primary': messageToShow !== 'Customer created successfully!' }"
class="alert alert-dismissible fade fade-in show text-white"
role="alert"
>
<strong>{{ messageToShow }}</strong>
</div>
</div>
<div class="form-group">
<input
class="form-control form-control-sm"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ import { CreateCustomerComponent } from './create-customer';
import { CustomerState, CreateCustomer } from 'src/app/modules/customer-management/store';
import { ResetCustomerToEdit, UpdateCustomer } from './../../../../store/customer-management.actions';
import { Customer } from 'src/app/modules/shared/models';
import { ToastrService, IndividualConfig } from 'ngx-toastr';

describe('CreateCustomerComponent', () => {
let component: CreateCustomerComponent;
let fixture: ComponentFixture<CreateCustomerComponent>;
let store: MockStore<CustomerState>;
const toastrService = {
success: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { },
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { }
};

const state = {
data: [],
Expand All @@ -28,17 +33,19 @@ describe('CreateCustomerComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [CreateCustomerComponent],
providers: [FormBuilder, provideMockStore({ initialState: state })],
providers: [
FormBuilder,
provideMockStore({ initialState: state }),
{ provide: ToastrService, useValue: toastrService },
],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(CreateCustomerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
store = TestBed.inject(MockStore);
store.setState(state);
});
}));

afterEach(() => {
fixture.destroy();
Expand Down Expand Up @@ -87,30 +94,20 @@ describe('CreateCustomerComponent', () => {

it('should be enable tabs and show message Customer created successfully! ', () => {
component.areTabsActive = false;
component.messageToShow = '';

spyOn(store, 'dispatch');

component.ngOnInit();
component.onSubmit(customerData);
component.setStatusOnScreen('Customer created successfully!');

expect(component.messageToShow).toEqual('Customer created successfully!');
expect(component.areTabsActive).toBeTrue();
});

it('should be disabled tabs and show message An error occurred, try again later. ', () => {
component.areTabsActive = false;
component.messageToShow = '';

spyOn(store, 'dispatch');

component.ngOnInit();
component.onSubmit(customerData);
component.setStatusOnScreen('An error occurred, try again later.');

expect(component.messageToShow).toEqual('An error occurred, try again later.');
expect(component.areTabsActive).toBeFalse();
expect(component.areTabsActive).toBeTruthy();
});

it('set data to update ', () => {
Expand All @@ -119,6 +116,6 @@ describe('CreateCustomerComponent', () => {
component.ngOnInit();
component.setDataToUpdate(customerData);

expect(component.messageToShow).toEqual(undefined);
expect(store.dispatch).toHaveBeenCalledTimes(2);
});
});
Loading