Skip to content

Commit a6f248b

Browse files
authored
close #87- save customers
close #87- save customers
2 parents 3e9d621 + b2a4427 commit a6f248b

File tree

54 files changed

+492
-109
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+492
-109
lines changed

src/app/app-routing.module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { TimeEntriesComponent } from './modules/time-entries/pages/time-entries.
88
import { ActivitiesManagementComponent } from './modules/activities-management/pages/activities-management.component';
99
import { HomeComponent } from './modules/home/home.component';
1010
import { LoginComponent } from './modules/login/login.component';
11-
import { CustomerComponent } from './modules/customer-managment/pages/customer.component';
11+
import { CustomerComponent } from './modules/customer-management/pages/customer.component';
1212

1313
const routes: Routes = [
1414
{

src/app/app.module.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,20 @@ import { ProjectEffects } from './modules/project-management/store/project.effec
3636
import { TechnologyEffects } from './modules/shared/store/technology.effects';
3737
import { reducers, metaReducers } from './reducers';
3838
import { environment } from '../environments/environment';
39-
import { CustomerComponent } from './modules/customer-managment/pages/customer.component';
39+
import { CustomerComponent } from './modules/customer-management/pages/customer.component';
4040
// tslint:disable-next-line: max-line-length
41-
import { CustomerListComponent } from './modules/customer-managment/components/customer-info/components/customer-list/customer-list.component';
42-
import { SearchComponent } from './modules/customer-managment/components/search/search.component';
41+
import { CustomerListComponent } from './modules/customer-management/components/customer-info/components/customer-list/customer-list.component';
4342
// tslint:disable-next-line: max-line-length
44-
import { ManagementCustomerProjectsComponent } from './modules/customer-managment/components/management-customer-projects/management-customer-projects.component';
45-
import { CreateCustomerComponent } from './modules/customer-managment/components/customer-info/components/create-customer/create-customer';
43+
import { ManagementCustomerProjectsComponent } from './modules/customer-management/components/management-customer-projects/management-customer-projects.component';
44+
import { CreateCustomerComponent } from './modules/customer-management/components/customer-info/components/create-customer/create-customer';
4645
// tslint:disable-next-line: max-line-length
47-
import { CreateProjectComponent } from './modules/customer-managment/components/projects/components/create-project/create-project.component';
48-
import { ProjectListComponent } from './modules/customer-managment/components/projects/components/project-list/project-list.component';
46+
import { CreateProjectComponent } from './modules/customer-management/components/projects/components/create-project/create-project.component';
47+
import { ProjectListComponent } from './modules/customer-management/components/projects/components/project-list/project-list.component';
4948
// tslint:disable-next-line: max-line-length
50-
import { ProjectTypeListComponent } from './modules/customer-managment/components/projects-type/components/project-type-list/project-type-list.component';
49+
import { ProjectTypeListComponent } from './modules/customer-management/components/projects-type/components/project-type-list/project-type-list.component';
5150
// tslint:disable-next-line: max-line-length
52-
import { CreateProjectTypeComponent } from './modules/customer-managment/components/projects-type/components/create-project-type/create-project-type.component';
51+
import { CreateProjectTypeComponent } from './modules/customer-management/components/projects-type/components/create-project-type/create-project-type.component';
52+
import { CustomerEffects } from './modules/customer-management/store/customer-management.effects';
5353

5454
@NgModule({
5555
declarations: [
@@ -77,7 +77,6 @@ import { CreateProjectTypeComponent } from './modules/customer-managment/compone
7777
SearchProjectComponent,
7878
CustomerComponent,
7979
CustomerListComponent,
80-
SearchComponent,
8180
ManagementCustomerProjectsComponent,
8281
CreateCustomerComponent,
8382
CreateProjectComponent,
@@ -102,7 +101,7 @@ import { CreateProjectTypeComponent } from './modules/customer-managment/compone
102101
maxAge: 15, // Retains last 15 states
103102
})
104103
: [],
105-
EffectsModule.forRoot([ProjectEffects, ActivityEffects, TechnologyEffects]),
104+
EffectsModule.forRoot([ProjectEffects, ActivityEffects, CustomerEffects, TechnologyEffects]),
106105
],
107106
providers: [],
108107
bootstrap: [AppComponent],
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<div class="container">
2+
<form style="width: 600px;" [formGroup]="customerForm" (ngSubmit)="onSubmit(customerForm.value)">
3+
<div class="form-group">
4+
<div
5+
*ngIf="showAlert && messageToShow !== ''"
6+
[ngClass]="{'bg-secondary': messageToShow == 'Customer created successfully!', 'bg-primary': messageToShow != 'Customer created successfully!'}"
7+
class="alert alert-dismissible fade fade-in show text-white"
8+
role="alert"
9+
>
10+
<strong>{{ messageToShow }}</strong>
11+
</div>
12+
13+
<input
14+
class="form-control form-control-sm"
15+
id="name"
16+
type="text"
17+
formControlName="name"
18+
placeholder="Customer name"
19+
[class.is-invalid]="customerForm.invalid && customerForm.touched"
20+
required
21+
/>
22+
<span
23+
class="badge badge-pill badge-light text-danger"
24+
*ngIf="(customerForm.dirty || customerForm.touched) && customerForm.invalid"
25+
>Activity name is required</span
26+
>
27+
<textarea
28+
class="form-control form-control-sm mt-2"
29+
id="description"
30+
rows="3"
31+
formControlName="description"
32+
placeholder="Customer description"
33+
></textarea>
34+
<button type="submit" class="btn btn-sm btn-primary" [disabled]="!customerForm.valid">Save</button>
35+
<button (click)="resetCustomerForm()" id="cancel" type="button" class="btn btn-sm btn-secondary mb-2 ml-2 mt-2">
36+
Cancel
37+
</button>
38+
</div>
39+
</form>
40+
</div>
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { FormBuilder } from '@angular/forms';
3+
import { MockStore, provideMockStore } from '@ngrx/store/testing';
4+
5+
import { CreateCustomerComponent } from './create-customer';
6+
import { CustomerState, CreateCustomer } from 'src/app/modules/customer-management/store';
7+
import * as models from 'src/app/modules/shared/models/index';
8+
9+
describe('CreateCustomerComponent', () => {
10+
let component: CreateCustomerComponent;
11+
let fixture: ComponentFixture<CreateCustomerComponent>;
12+
let store: MockStore<CustomerState>;
13+
14+
const state = {
15+
data: [],
16+
isLoading: false,
17+
message: '',
18+
};
19+
20+
const customerData: models.Customer = {
21+
name: 'aa',
22+
description: 'bb',
23+
tenant_id: 'cc',
24+
};
25+
26+
beforeEach(async(() => {
27+
TestBed.configureTestingModule({
28+
declarations: [CreateCustomerComponent],
29+
providers: [FormBuilder, provideMockStore({ initialState: state })],
30+
}).compileComponents();
31+
}));
32+
33+
beforeEach(() => {
34+
fixture = TestBed.createComponent(CreateCustomerComponent);
35+
component = fixture.componentInstance;
36+
fixture.detectChanges();
37+
38+
store = TestBed.inject(MockStore);
39+
store.setState(state);
40+
});
41+
42+
afterEach(() => {
43+
fixture.destroy();
44+
});
45+
46+
it('component should be created', () => {
47+
expect(component).toBeTruthy();
48+
});
49+
50+
it('should call resetCustomerForm', () => {
51+
spyOn(component.customerForm, 'reset');
52+
53+
component.resetCustomerForm();
54+
55+
expect(component.customerForm.reset).toHaveBeenCalled();
56+
});
57+
58+
it('onSubmit and dispatch CreateCustomer action', () => {
59+
spyOn(store, 'dispatch');
60+
61+
component.onSubmit(customerData);
62+
63+
expect(store.dispatch).toHaveBeenCalledTimes(1);
64+
expect(store.dispatch).toHaveBeenCalledWith(new CreateCustomer(customerData));
65+
});
66+
67+
it('should call resetCustomerForm', () => {
68+
spyOn(component.customerForm, 'reset');
69+
70+
component.resetCustomerForm();
71+
72+
expect(component.customerForm.reset).toHaveBeenCalled();
73+
});
74+
75+
it('should be enable tabs and show message Customer created successfully! ', () => {
76+
component.areTabsActive = false;
77+
component.messageToShow = '';
78+
79+
spyOn(store, 'dispatch');
80+
81+
component.ngOnInit();
82+
83+
component.onSubmit(customerData);
84+
85+
component.setStatusOnScreen('Customer created successfully!');
86+
87+
expect(component.messageToShow).toEqual('Customer created successfully!');
88+
expect(component.areTabsActive).toBeTrue();
89+
});
90+
91+
it('should be disabled tabs and show message An error occurred, try again later. ', () => {
92+
component.areTabsActive = false;
93+
component.messageToShow = '';
94+
95+
spyOn(store, 'dispatch');
96+
97+
component.ngOnInit();
98+
99+
component.onSubmit(customerData);
100+
101+
component.setStatusOnScreen('An error occurred, try again later.');
102+
103+
expect(component.messageToShow).toEqual('An error occurred, try again later.');
104+
expect(component.areTabsActive).toBeFalse();
105+
});
106+
});
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { Component, Input, Output, EventEmitter, OnDestroy, OnInit } from '@angular/core';
2+
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
3+
import { Store, select } from '@ngrx/store';
4+
5+
import { Subscription } from 'rxjs';
6+
import { CustomerState, CreateCustomer } from 'src/app/modules/customer-management/store';
7+
import { getStatusMessage } from 'src/app/modules/customer-management/store/customer-management.selectors';
8+
9+
@Component({
10+
selector: 'app-create-customer',
11+
templateUrl: './create-customer.html',
12+
styleUrls: ['./create-customer.scss'],
13+
})
14+
export class CreateCustomerComponent implements OnInit, OnDestroy {
15+
customerForm: FormGroup;
16+
@Input() areTabsActive: boolean;
17+
@Output() changeValueAreTabsActives = new EventEmitter<boolean>();
18+
showAlert = false;
19+
messageToShow = '';
20+
saveSubscription: Subscription;
21+
22+
constructor(private formBuilder: FormBuilder, private store: Store<CustomerState>) {
23+
this.customerForm = this.formBuilder.group({
24+
name: ['', Validators.required],
25+
description: [''],
26+
});
27+
}
28+
29+
ngOnInit() {
30+
const messages$ = this.store.pipe(select(getStatusMessage));
31+
this.saveSubscription = messages$.subscribe((valueMessage) => {
32+
this.setStatusOnScreen(valueMessage);
33+
});
34+
}
35+
36+
ngOnDestroy() {
37+
this.areTabsActive = false;
38+
this.saveSubscription.unsubscribe();
39+
}
40+
41+
onSubmit(customerData) {
42+
this.store.dispatch(new CreateCustomer(customerData));
43+
this.showAlert = true;
44+
}
45+
46+
setStatusOnScreen(message: string) {
47+
if (message === 'Customer created successfully!') {
48+
this.messageToShow = message;
49+
this.areTabsActive = true;
50+
this.changeValueAreTabsActives.emit(this.areTabsActive);
51+
} else if (message === 'An error occurred, try again later.') {
52+
this.messageToShow = message;
53+
this.areTabsActive = false;
54+
this.changeValueAreTabsActives.emit(this.areTabsActive);
55+
}
56+
}
57+
58+
resetCustomerForm() {
59+
this.showAlert = false;
60+
this.customerForm.reset();
61+
}
62+
}

0 commit comments

Comments
 (0)