-
Notifications
You must be signed in to change notification settings - Fork 1
87 save customers #139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
87 save customers #139
Changes from 1 commit
016d0c6
d038c10
4863d19
f2f62e4
2cc4c8c
2e9aef9
b760c32
925becb
d4ff348
b2a4427
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| <div class="container"> | ||
| <form style="width: 600px;" [formGroup]="customerForm" (ngSubmit)="onSubmit(customerForm.value)"> | ||
| <div class="form-group"> | ||
| <div | ||
| *ngIf="messageToShow != ''" | ||
| [ngClass]="{'bg-secondary': messageToShow == 'Data create successfully!', 'bg-primary': messageToShow != 'Data create successfully!'}" | ||
| class="alert alert-dismissible fade fade-in show text-white" | ||
| role="alert" | ||
| > | ||
| <strong>{{ messageToShow }}</strong> | ||
| <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | ||
| <span aria-hidden="true">×</span> | ||
| </button> | ||
| </div> | ||
|
|
||
| <input | ||
| class="form-control form-control-sm" | ||
| id="name" | ||
| type="text" | ||
| formControlName="name" | ||
| placeholder="Customer name" | ||
| [class.is-invalid]="customerForm.invalid && customerForm.touched" | ||
| required | ||
| /> | ||
| <span | ||
| class="badge badge-pill badge-light text-danger" | ||
| *ngIf="(customerForm.dirty || customerForm.touched) && customerForm.invalid" | ||
| >Activity name is required</span | ||
| > | ||
| <textarea | ||
| class="form-control form-control-sm mt-2" | ||
| id="description" | ||
| rows="3" | ||
| formControlName="description" | ||
| placeholder="Customer description" | ||
| ></textarea> | ||
| <button type="submit" class="btn btn-sm btn-primary" [disabled]="!customerForm.valid">Save</button> | ||
| <button (click)="resetCustomerForm()" id="cancel" type="button" class="btn btn-sm btn-secondary mb-2 ml-2 mt-2"> | ||
| Cancel | ||
| </button> | ||
| </div> | ||
| </form> | ||
| </div> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| import { async, ComponentFixture, TestBed } from '@angular/core/testing'; | ||
|
|
||
| import { CreateCustomerComponent } from './create-customer'; | ||
| import { MockStore, provideMockStore } from '@ngrx/store/testing'; | ||
| import { CustomerState, CreateCustomer, CreateCustomerSuccess } from 'src/app/modules/customer-management/store'; | ||
| import { FormBuilder, FormGroup } from '@angular/forms'; | ||
| import { By } from '@angular/platform-browser'; | ||
| import { Customer } from 'src/app/modules/shared/models/customer.model'; | ||
| import { of } from 'rxjs'; | ||
|
|
||
| describe('CreateCustomerComponent', () => { | ||
| let component: CreateCustomerComponent; | ||
| let fixture: ComponentFixture<CreateCustomerComponent>; | ||
| let store: MockStore<CustomerState>; | ||
|
|
||
| const state = { | ||
| data: [], | ||
| isLoading: false, | ||
| message: '', | ||
| }; | ||
|
|
||
| const message = { | ||
| message() { | ||
| const messageValue = 'Sucess'; | ||
| return messageValue; | ||
| }, | ||
| }; | ||
|
|
||
| beforeEach(async(() => { | ||
| TestBed.configureTestingModule({ | ||
| declarations: [CreateCustomerComponent], | ||
| providers: [FormBuilder, provideMockStore({ initialState: state })], | ||
| }).compileComponents(); | ||
| })); | ||
|
|
||
| beforeEach(() => { | ||
| fixture = TestBed.createComponent(CreateCustomerComponent); | ||
| component = fixture.componentInstance; | ||
| fixture.detectChanges(); | ||
|
|
||
| store = TestBed.inject(MockStore); | ||
| store.setState(state); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| fixture.destroy(); | ||
| }); | ||
|
|
||
| it('component should be created', () => { | ||
| expect(component).toBeTruthy(); | ||
| }); | ||
|
|
||
| it('should call resetCustomerForm', async(() => { | ||
| spyOn(component.customerForm, 'reset'); | ||
|
|
||
| component.resetCustomerForm(); | ||
|
|
||
| expect(component.customerForm.reset).toHaveBeenCalled(); | ||
| })); | ||
|
|
||
| it('onSubmit and dispatch CreateCustomer action', async(() => { | ||
| const customerData: Customer = { | ||
| name: 'aa', | ||
| description: 'bb', | ||
| tenant_id: 'cc', | ||
| }; | ||
|
|
||
| spyOn(store, 'dispatch'); | ||
|
|
||
| component.onSubmit(customerData); | ||
|
|
||
| expect(store.dispatch).toHaveBeenCalledTimes(1); | ||
| expect(store.dispatch).toHaveBeenCalledWith(new CreateCustomer(customerData)); | ||
| })); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| import { Component, Input, Output, EventEmitter } from '@angular/core'; | ||
| import { Store } from '@ngrx/store'; | ||
| import { CustomerState, CreateCustomer } from 'src/app/modules/customer-management/store'; | ||
| import { FormGroup, FormBuilder, Validators } from '@angular/forms'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please sort imports by module.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
|
||
| @Component({ | ||
| selector: 'app-create-customer', | ||
| templateUrl: './create-customer.html', | ||
| styleUrls: ['./create-customer.scss'], | ||
| }) | ||
| export class CreateCustomerComponent { | ||
| customerForm: FormGroup; | ||
| @Input() isActiveItemTabs: boolean; | ||
|
||
| @Output() changeValueIsActiveItemTabs = new EventEmitter<boolean>(); | ||
| showSuccessAlert = false; | ||
| messageToShow = ''; | ||
| response = ''; | ||
|
|
||
| constructor(private formBuilder: FormBuilder, private store: Store<CustomerState>) { | ||
| this.customerForm = this.formBuilder.group({ | ||
| name: ['', Validators.required], | ||
| description: [''], | ||
| }); | ||
| } | ||
|
|
||
| onSubmit(customerData) { | ||
| this.store.dispatch(new CreateCustomer(customerData)); | ||
| this.store | ||
| .select((state) => state) | ||
| .subscribe((state) => { | ||
| this.response = Object.values(state)[2].message; | ||
| if (this.response === 'Data create successfully!') { | ||
| this.isActiveItemTabs = true; | ||
| this.changeValueIsActiveItemTabs.emit(this.isActiveItemTabs); | ||
| this.messageToShow = this.response; | ||
| } else { | ||
| this.messageToShow = this.response; | ||
| } | ||
| }); | ||
| this.messageToShow = ''; | ||
| } | ||
|
|
||
| resetCustomerForm() { | ||
| this.customerForm.reset(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,12 @@ | ||
| import { Component } from '@angular/core'; | ||
| import { Component, Input } from '@angular/core'; | ||
|
|
||
| @Component({ | ||
| selector: 'app-management-customer-projects', | ||
| templateUrl: './management-customer-projects.component.html', | ||
| styleUrls: ['./management-customer-projects.component.scss'], | ||
| }) | ||
| export class ManagementCustomerProjectsComponent { | ||
| isActiveNavsItemTabs = false; | ||
|
|
||
| constructor() {} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import { TestBed, inject } from '@angular/core/testing'; | ||
|
|
||
| import { CustomerService } from './customer.service'; | ||
| import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; | ||
|
||
| import { Customer } from '../../shared/models/customer.model'; | ||
|
|
||
| describe('CustomerService', () => { | ||
| let service: CustomerService; | ||
| let httpMock: HttpTestingController; | ||
|
|
||
| beforeEach(() => { | ||
| TestBed.configureTestingModule({ imports: [HttpClientTestingModule] }); | ||
| service = TestBed.inject(CustomerService); | ||
| httpMock = TestBed.inject(HttpTestingController); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| httpMock.verify(); | ||
| }); | ||
|
|
||
| it('services are ready to be used', inject( | ||
| [HttpClientTestingModule, CustomerService], | ||
| (httpClient: HttpClientTestingModule, customerService: CustomerService) => { | ||
| expect(customerService).toBeTruthy(); | ||
| expect(httpClient).toBeTruthy(); | ||
| } | ||
| )); | ||
|
|
||
| it('create customer using POST from baseUrl', () => { | ||
| const customer: Customer[] = [{ name: 'aa', description: 'bb', tenant_id: 'cc' }]; | ||
|
|
||
| service.baseUrl = 'customers'; | ||
|
|
||
| service.createCustomer(customer).subscribe((response) => { | ||
| expect(response.length).toBe(1); | ||
| }); | ||
|
|
||
| const createCustomerRequest = httpMock.expectOne(service.baseUrl); | ||
| expect(createCustomerRequest.request.method).toBe('POST'); | ||
| createCustomerRequest.flush(customer); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import { Injectable } from '@angular/core'; | ||
| import { HttpClient } from '@angular/common/http'; | ||
| import { environment } from './../../../../environments/environment'; | ||
| import { Observable } from 'rxjs'; | ||
|
|
||
| @Injectable({ | ||
| providedIn: 'root', | ||
| }) | ||
| export class CustomerService { | ||
| baseUrl = `${environment.timeTrackerApiUrl}/customers`; | ||
|
|
||
| constructor(private http: HttpClient) {} | ||
|
|
||
| createCustomer(customerData): Observable<any> { | ||
| const body = { | ||
| ...customerData, | ||
| tenant_id: '4225ab1e-1033-4a5f-8650-0dd4950f38c8', | ||
|
||
| }; | ||
| return this.http.post(this.baseUrl, body); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import * as actions from './customer-management.actions'; | ||
|
|
||
| describe('CustomerManagmentActions', () => { | ||
| it('CreateCustomer type is CustomerManagementActionTypes.CREATE_CUSTOMER', () => { | ||
| const createActivity = new actions.CreateCustomer({ | ||
| name: 'aa', | ||
| description: 'bb', | ||
| tenant_id: 'cc', | ||
| }); | ||
| expect(createActivity.type).toEqual(actions.CustomerManagementActionTypes.CREATE_CUSTOMER); | ||
| }); | ||
|
|
||
| it('CreateCustomerSuccess type is CustomerManagementActionTypes.CREATE_CUSTOMER_SUCCES', () => { | ||
| const createActivitySuccess = new actions.CreateCustomerSuccess({ | ||
| name: 'aa', | ||
| description: 'bb', | ||
| tenant_id: 'cc', | ||
| }); | ||
| expect(createActivitySuccess.type).toEqual(actions.CustomerManagementActionTypes.CREATE_CUSTOMER_SUCCESS); | ||
| }); | ||
|
|
||
| it('CreateCustomerFail type is CustomerManagementActionTypes.CREATE_CUSTOMER_FAIL', () => { | ||
| const createActivityFail = new actions.CreateCustomerFail('error'); | ||
| expect(createActivityFail.type).toEqual(actions.CustomerManagementActionTypes.CREATE_CUSTOMER_FAIL); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { Action } from '@ngrx/store'; | ||
| import { Customer } from '../../shared/models/customer.model'; | ||
|
|
||
| export enum CustomerManagementActionTypes { | ||
| CREATE_CUSTOMER = '[CustomerManagement] CREATE_CUSTOMER', | ||
| CREATE_CUSTOMER_SUCCESS = '[CustomerManagement] CREATE_CUSTOMER_SUCCESS', | ||
| CREATE_CUSTOMER_FAIL = '[CustomerManagement] CREATE_CUSTOMER_FAIL', | ||
| } | ||
|
|
||
| export class CreateCustomer implements Action { | ||
| public readonly type = CustomerManagementActionTypes.CREATE_CUSTOMER; | ||
|
|
||
| constructor(public payload: Customer) {} | ||
| } | ||
|
|
||
| export class CreateCustomerSuccess implements Action { | ||
| public readonly type = CustomerManagementActionTypes.CREATE_CUSTOMER_SUCCESS; | ||
|
|
||
| constructor(public payload: Customer) {} | ||
| } | ||
|
|
||
| export class CreateCustomerFail implements Action { | ||
| public readonly type = CustomerManagementActionTypes.CREATE_CUSTOMER_FAIL; | ||
|
|
||
| constructor(public error: string) {} | ||
| } | ||
|
|
||
| export type CustomerManagementActions = CreateCustomer | CreateCustomerSuccess | CreateCustomerFail; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The customer.model must be added in the index file in 'src/app/modules/shared/models/index.ts'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done