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 @@ -8,35 +8,36 @@
>
<thead class="thead-blue">
<tr class="d-flex">
<th class="col-5 text-center">Customer ID</th>
<th class="col-3 text-center">Name</th>
<th class="col-4 text-center">Options</th>
<th class="col-4 text-center">Customer ID</th>
<th class="col-4 text-center">Name</th>
<th class="col-2 text-center">Options</th>
<th class="col-2 text-center">Visibility</th>
</tr>
</thead>
<app-loading-bar *ngIf="(isLoading$ | async)"></app-loading-bar>
<tbody *ngIf="((isLoading$ | async) === false)">
<tr class="d-flex" *ngFor="let customer of customers">
<td class="col-5 text-break">{{ customer.id }}</td>
<td class="col-3 text-break">{{ customer.name }}</td>
<td class="col-4 text-center">
<button
data-toggle="modal"
(click)="editCustomer(customer.id)"
type="button"
data-target="#editModal"
class="btn btn-sm btn-primary"
>
<td class="col-4 text-break">{{ customer.id }}</td>
<td class="col-4 text-break">{{ customer.name }}</td>
<td class="col-2 text-center">
<button
data-toggle="modal"
(click)="editCustomer(customer.id)"
type="button" data-target="#editModal"
class="btn btn-sm btn-primary">
<i class="fa fa-pen fa-xs"></i>
</button>

<button
data-toggle="modal"
data-target="#deleteModal"
(click)="openModal(customer)"
type="button"
class="btn btn-sm btn-danger ml-2"
</td>
<td class="col-2 text-center">
<button
class="btn btn-sm"
data-toggle="modal"
data-target="#deleteModal"
[ngClass]="customer.btnColor"
(click)="switchStatus(customer)"
>
<i class="fa fa-trash-alt fa-xs"></i>
<i class="fa" [ngClass]="customer.btnIcon" ></i>
{{customer.btnName}}
</button>
</td>
</tr>
Expand Down Expand Up @@ -68,4 +69,4 @@
[body]="message"
(closeModalEvent)="closeModal()"
>
</app-dialog>
</app-dialog>
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,39 @@ describe('CustomerTableListComponent', () => {
const actionSub: ActionsSubject = new ActionsSubject();

const state = {
data: [{ tenant_id: 'id', name: 'name', description: 'description' }],
data: [{ tenant_id: 'id', name: 'name', description: 'description', status: 'inactive' }],
isLoading: false,
message: '',
customerIdToEdit: '',
customerId: '',
};

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [NgxPaginationModule, DataTablesModule],
declarations: [CustomerListComponent],
providers: [provideMockStore({ initialState: state }), { provide: ActionsSubject, useValue: actionSub }],
}).compileComponents();
}));
const btnProps = [
{
key: 'active',
_status: false,
btnColor: 'btn-danger',
btnIcon: 'fa-arrow-circle-down',
btnName: 'Archive',
},
{
key: 'inactive',
_status: true,
btnColor: 'btn-primary',
btnIcon: 'fa-arrow-circle-up',
btnName: 'Active',
},
];

beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
imports: [NgxPaginationModule, DataTablesModule],
declarations: [CustomerListComponent],
providers: [provideMockStore({ initialState: state }), { provide: ActionsSubject, useValue: actionSub }],
}).compileComponents();
})
);

beforeEach(() => {
fixture = TestBed.createComponent(CustomerListComponent);
Expand Down Expand Up @@ -175,7 +194,12 @@ describe('CustomerTableListComponent', () => {

actionSubject.next(action);

expect(component.customers).toEqual(state.data);
const StateWithBtnProperties = state.data.map((customer) => {
const addProps = btnProps.find((prop) => prop.key === component.setActive(customer.status));
return { ...customer, ...addProps };
});

expect(component.customers).toEqual(StateWithBtnProperties);
});

it('on success load customer, the datatable should be reloaded', async () => {
Expand All @@ -191,6 +215,60 @@ describe('CustomerTableListComponent', () => {
expect(component.dtElement.dtInstance.then).toHaveBeenCalled();
});

it('openModal should set on true and display "Are you sure you want to archive customer"', () => {
const message = 'Are you sure you want to archive name?';
const itemData = {
id: '1',
name: 'name',
description: 'description',
status: 'active',
key: 'active',
_status: false,
btnColor: 'btn-danger',
btnIcon: 'fa-arrow-circle-down',
btnName: 'Archive',
};

component.openModal(itemData);
expect(component.showModal).toBeTrue();
expect(component.message).toBe(message);
});

it('switchStatus should call openModal() on item.status = activate', () => {
const itemData = {
id: '1',
name: 'name',
description: 'description',
status: 'activate',
key: 'activate',
_status: false,
btnColor: 'btn-danger',
btnIcon: 'fa-arrow-circle-down',
btnName: 'Archive',
};

spyOn(component, 'openModal');
component.switchStatus(itemData);
expect(component.openModal).toHaveBeenCalled();
});

it('switchStatus should set showModal false when item.status = inactive', () => {
const itemData = {
id: '1',
name: 'name',
description: 'description',
status: 'inactive',
key: 'inactive',
_status: true,
btnColor: 'btn-primary',
btnIcon: 'fa-arrow-circle-up',
btnName: 'Active',
};

component.switchStatus(itemData);
expect(component.showModal).toBeFalse();
});

afterEach(() => {
component.dtTrigger.unsubscribe();
component.changeCustomerSubscription.unsubscribe();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { Observable, Subject, Subscription } from 'rxjs';
import { delay, filter } from 'rxjs/operators';
import {
customerIdtoEdit,
getIsLoading
getIsLoading,
} from 'src/app/modules/customer-management/store/customer-management.selectors';
import { Customer } from './../../../../../shared/models/customer.model';
import { Customer, CustomerUI } from './../../../../../shared/models/customer.model';
import {
CustomerManagementActionTypes,
DeleteCustomer,
Expand All @@ -17,6 +17,7 @@ import {
} from './../../../../store/customer-management.actions';
import { ResetProjectToEdit, SetProjectToEdit } from '../../../projects/components/store/project.actions';
import { ResetProjectTypeToEdit, SetProjectTypeToEdit } from '../../../projects-type/store';
import { UnarchiveCustomer } from '../../../../store/customer-management.actions';

@Component({
selector: 'app-customer-list',
Expand All @@ -28,7 +29,7 @@ export class CustomerListComponent implements OnInit, OnDestroy, AfterViewInit {
@Input() hasChange: boolean;
@Output() changeValueShowCustomerForm = new EventEmitter<boolean>();
@Input()
customers: Customer[] = [];
customers: CustomerUI[] = [];
dtOptions: any = {};
dtTrigger: Subject<any> = new Subject();
@ViewChild(DataTableDirective, { static: false })
Expand All @@ -48,6 +49,23 @@ export class CustomerListComponent implements OnInit, OnDestroy, AfterViewInit {
}

ngOnInit(): void {
const btnProps = [
{
key: 'active',
_status: false,
btnColor: 'btn-danger',
btnIcon: 'fa-arrow-circle-down',
btnName: 'Archive',
},
{
key: 'inactive',
_status: true,
btnColor: 'btn-primary',
btnIcon: 'fa-arrow-circle-up',
btnName: 'Active',
},
];

this.dtOptions = {
scrollY: '325px',
paging: false,
Expand All @@ -62,7 +80,10 @@ export class CustomerListComponent implements OnInit, OnDestroy, AfterViewInit {
this.loadCustomersSubscription = this.actionsSubject$
.pipe(filter((action: any) => action.type === CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS))
.subscribe((action) => {
this.customers = action.payload;
this.customers = action.payload.map((customer: CustomerUI) => {
const addProps = btnProps.find((prop) => prop.key === this.setActive(customer.status));
return { ...customer, ...addProps };
});
this.rerenderDataTable();
});
this.changeCustomerSubscription = this.actionsSubject$
Expand Down Expand Up @@ -151,7 +172,20 @@ export class CustomerListComponent implements OnInit, OnDestroy, AfterViewInit {

openModal(item: Customer) {
this.idToDelete = item.id;
this.message = `Are you sure you want to delete ${item.name}?`;
this.message = `Are you sure you want to archive ${item.name}?`;
this.showModal = true;
}

switchStatus(item: CustomerUI): void {
if (item.key !== 'inactive') {
this.openModal(item);
} else {
this.showModal = false;
this.store.dispatch(new UnarchiveCustomer(item.id));
}
}

setActive(status: any): string {
return status === 'inactive' ? 'inactive' : 'active';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,22 @@ describe('CustomerManagmentActions', () => {
const resetCustomerIdToEdit = new actions.ResetCustomerToEdit();
expect(resetCustomerIdToEdit.type).toEqual(actions.CustomerManagementActionTypes.RESET_CUSTOMER_ID_TO_EDIT);
});

it('UnarchiveCustomer type is CustomerManagementActionTypes.UNARCHIVE_CUSTOMER', () => {
const unArchiveCustomer = new actions.UnarchiveCustomer('id_test');
expect(unArchiveCustomer.type).toEqual(actions.CustomerManagementActionTypes.UNARCHIVE_CUSTOMER);
});

it('UnarchiveCustomerSuccess type is CustomerManagementActionTypes.UNARCHIVE_CUSTOMER_SUCCESS', () => {
const unArchiveCustomerSuccess = new actions.UnarchiveCustomerSuccess({
id: 'id_test',
status: 'active',
});
expect(unArchiveCustomerSuccess.type).toEqual(actions.CustomerManagementActionTypes.UNARCHIVE_CUSTOMER_SUCCESS);
});

it('UnarchiveCustomerFail type is CustomerManagementActionTypes.UNARCHIVE_CUSTOMER_FAIL', () => {
const unArchiveCustomerFail = new actions.UnarchiveCustomerFail('error');
expect(unArchiveCustomerFail.type).toEqual(actions.CustomerManagementActionTypes.UNARCHIVE_CUSTOMER_FAIL);
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Action } from '@ngrx/store';
import { Customer } from '../../shared/models/customer.model';
import { Customer, Status } from '../../shared/models/customer.model';

export enum CustomerManagementActionTypes {
CREATE_CUSTOMER = '[CustomerManagement] CREATE_CUSTOMER',
Expand All @@ -16,6 +16,9 @@ export enum CustomerManagementActionTypes {
UPDATE_CUSTOMER_FAIL = '[CustomerManagement] UPDATE_CUSTOMER_FAIL',
SET_CUSTOMER_ID_TO_EDIT = '[CustomerManagement] SET_CUSTOMER_ID_TO_EDIT',
RESET_CUSTOMER_ID_TO_EDIT = '[CustomerManagement] RESET_CUSTOMER_ID_TO_EDIT',
UNARCHIVE_CUSTOMER = '[CustomerManagement] UNARCHIVE_CUSTOMER',
UNARCHIVE_CUSTOMER_SUCCESS = '[CustomerManagement] UNARCHIVE_CUSTOMER_SUCCESS',
UNARCHIVE_CUSTOMER_FAIL = '[CustomerManagement] UNARCHIVE_CUSTOMER_FAIL',
}

export class LoadCustomers implements Action {
Expand Down Expand Up @@ -97,6 +100,24 @@ export class ResetCustomerToEdit implements Action {
public readonly type = CustomerManagementActionTypes.RESET_CUSTOMER_ID_TO_EDIT;
}

export class UnarchiveCustomer implements Action {
public readonly type = CustomerManagementActionTypes.UNARCHIVE_CUSTOMER;

constructor(public payload: string) {}
}

export class UnarchiveCustomerSuccess implements Action {
public readonly type = CustomerManagementActionTypes.UNARCHIVE_CUSTOMER_SUCCESS;

constructor(public payload: Status) {}
}

export class UnarchiveCustomerFail implements Action {
public readonly type = CustomerManagementActionTypes.UNARCHIVE_CUSTOMER_FAIL;

constructor(public error: string) {}
}

export type CustomerManagementActions =
| CreateCustomer
| CreateCustomerSuccess
Expand All @@ -111,4 +132,7 @@ export type CustomerManagementActions =
| UpdateCustomerSuccess
| UpdateCustomerFail
| SetCustomerToEdit
| ResetCustomerToEdit;
| ResetCustomerToEdit
| UnarchiveCustomer
| UnarchiveCustomerSuccess
| UnarchiveCustomerFail;
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,27 @@ describe('CustomerEffects', () => {
expect(action.type).toEqual(CustomerManagementActionTypes.DELETE_CUSTOMER_FAIL);
});
});

it('action type is UNARCHIVE_CUSTOMER_SUCCESS when service is executed sucessfully', async () => {
const customerId = 'customerId';
actions$ = of({ type: CustomerManagementActionTypes.UNARCHIVE_CUSTOMER, customerId });
spyOn(toastrService, 'success');
spyOn(service, 'updateCustomer').and.returnValue(of(customer));

effects.updateCustomer$.subscribe((action) => {
expect(toastrService.success).toHaveBeenCalledWith(INFO_SAVED_SUCCESSFULLY);
expect(action.type).toEqual(CustomerManagementActionTypes.UNARCHIVE_CUSTOMER_SUCCESS);
});
});

it('action type is UNARCHIVE_CUSTOMER_FAIL when service fail in execution', async () => {
actions$ = of({ type: CustomerManagementActionTypes.UNARCHIVE_CUSTOMER, customer });
spyOn(toastrService, 'error');
spyOn(service, 'updateCustomer').and.returnValue(throwError({ error: { message: 'fail!' } }));

effects.updateCustomer$.subscribe((action) => {
expect(toastrService.error).toHaveBeenCalled();
expect(action.type).toEqual(CustomerManagementActionTypes.UNARCHIVE_CUSTOMER_FAIL);
});
});
});
Loading