Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9998ad83c2 | ||
|
|
4150bf1ed1 |
@@ -4,6 +4,7 @@ import { HttpClientModule } from '@angular/common/http';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
@@ -11,12 +12,16 @@ import { EmployeesComponent } from './components/employees/employees.component';
|
||||
import { NavBarComponent } from './components/employees/nav-bar/nav-bar.component';
|
||||
import { employeesReducer } from './ngrx/employees.reducer';
|
||||
import { EmployeesEffects } from './ngrx/employees.effects';
|
||||
import { ListComponent } from './components/employees/list/list.component';
|
||||
import { ItemComponent } from './components/employees/list/item/item.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
EmployeesComponent,
|
||||
NavBarComponent
|
||||
NavBarComponent,
|
||||
ListComponent,
|
||||
ItemComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@@ -24,7 +29,9 @@ import { EmployeesEffects } from './ngrx/employees.effects';
|
||||
HttpClientModule,
|
||||
StoreModule.forRoot({catalogState:employeesReducer}),
|
||||
EffectsModule.forRoot([EmployeesEffects]),
|
||||
StoreDevtoolsModule.instrument()
|
||||
StoreDevtoolsModule.instrument(),
|
||||
FormsModule,
|
||||
ReactiveFormsModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<div class="p-4">
|
||||
<app-nav-bar></app-nav-bar>
|
||||
|
||||
<ng-container *ngIf="employeesState$ | async as state" [ngSwitch]="state.dataState">
|
||||
<ng-container *ngSwitchCase="EmployeesStateEnum.INITIAL">
|
||||
<div class="p-2">Initial State</div>
|
||||
@@ -11,17 +12,7 @@
|
||||
<div class="p-2">{{state.errorMessage | json}}</div>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="EmployeesStateEnum.LOADED" class="p-4">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>ID</th><th>Nom</th><th>Prénom</th><th>Role</th>
|
||||
</tr>
|
||||
<tr *ngFor="let employee of state.employees">
|
||||
<td>{{employee.id}}</td>
|
||||
<td>{{employee.nom}}</td>
|
||||
<td>{{employee.prenom}}</td>
|
||||
<td>{{employee.role}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<app-list [state]="state"></app-list>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@@ -20,5 +20,4 @@ export class EmployeesComponent implements OnInit {
|
||||
map((state) => state.catalogState)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
17
src/app/components/employees/list/item/item.component.html
Normal file
17
src/app/components/employees/list/item/item.component.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<tr *ngIf="employee">
|
||||
<td>{{employee.id}}</td>
|
||||
<td>{{employee.nom}}</td>
|
||||
<td>{{employee.prenom}}</td>
|
||||
<td>{{employee.role}}</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-outline-danger" (click)="onDelete(employee)">
|
||||
<span class="fa fa-trash"></span>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-outline-info" (click)="onEdit(employee)">
|
||||
<span class="fa fa-edit"></span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ItemComponent } from './item.component';
|
||||
|
||||
describe('ItemComponent', () => {
|
||||
let component: ItemComponent;
|
||||
let fixture: ComponentFixture<ItemComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ItemComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ItemComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
21
src/app/components/employees/list/item/item.component.ts
Normal file
21
src/app/components/employees/list/item/item.component.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Employee } from '../../../../model/employee.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-item',
|
||||
templateUrl: './item.component.html',
|
||||
styleUrls: ['./item.component.css']
|
||||
})
|
||||
export class ItemComponent implements OnInit {
|
||||
@Input() employee:Employee|null=null;
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
onDelete(val:Employee) {
|
||||
}
|
||||
|
||||
onEdit(val:Employee) {
|
||||
}
|
||||
}
|
||||
13
src/app/components/employees/list/list.component.html
Normal file
13
src/app/components/employees/list/list.component.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<div class="container">
|
||||
<table class="table" *ngIf="state">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th><th>Nom</th><th>Prénom</th><th>Role</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<app-item [employee]="p" *ngFor="let p of state.employees" style="display: contents">
|
||||
</app-item>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
25
src/app/components/employees/list/list.component.spec.ts
Normal file
25
src/app/components/employees/list/list.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ListComponent } from './list.component';
|
||||
|
||||
describe('ListComponent', () => {
|
||||
let component: ListComponent;
|
||||
let fixture: ComponentFixture<ListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ListComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
15
src/app/components/employees/list/list.component.ts
Normal file
15
src/app/components/employees/list/list.component.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { EmployeesState } from '../../../ngrx/employees.reducer';
|
||||
|
||||
@Component({
|
||||
selector: 'app-list',
|
||||
templateUrl: './list.component.html',
|
||||
styleUrls: ['./list.component.css']
|
||||
})
|
||||
export class ListComponent implements OnInit {
|
||||
@Input() state?:EmployeesState|null=null;
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,20 @@
|
||||
<ul class="nav nav-pills">
|
||||
<li>
|
||||
<button class="btn btn-outline-info" (click)="onGetAllEmployees()">All</button>
|
||||
<nav class="navbar navbar-expand-sm bg-light navbar-light">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<button class="btn btn-outline-info btn-sm" (click)="onGetAllEmployees()">All</button>
|
||||
</li>
|
||||
<li class="nav-item ms-2">
|
||||
<button class="btn btn-outline-info btn-sm" (click)="onGetAllEmployees()">New</button>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<form #f="ngForm" (ngSubmit)="onSearch(f.value)" class="form-inline">
|
||||
<input type="text" ngModel name="keyword">
|
||||
<button type="submit" class="btn btn-outline-info btn-sm">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { GetAllEmployeesAction } from '../../../ngrx/employees.actions';
|
||||
import { GetAllEmployeesAction, SearchEmployeesAction } from '../../../ngrx/employees.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-nav-bar',
|
||||
@@ -17,4 +17,8 @@ export class NavBarComponent implements OnInit {
|
||||
onGetAllEmployees() {
|
||||
this.store.dispatch(new GetAllEmployeesAction({}))
|
||||
}
|
||||
|
||||
onSearch(val:any) {
|
||||
this.store.dispatch(new SearchEmployeesAction(val.keyword))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,27 +5,41 @@ export enum EmployeesActionsTypes {
|
||||
GET_ALL_EMPLOYEES="[Employees] Get All Employees",
|
||||
GET_ALL_EMPLOYEES_SUCCESS="[Employees] Get All Employees Success",
|
||||
GET_ALL_EMPLOYEES_ERROR="[Employees] Get All Employees Error",
|
||||
/* Search employees */
|
||||
SEARCH_EMPLOYEES="[Employees] Search Employees",
|
||||
SEARCH_EMPLOYEES_SUCCESS="[Employees] Search Success",
|
||||
SEARCH_EMPLOYEES_ERROR="[Employees] Search Employees Error",
|
||||
}
|
||||
|
||||
export class GetAllEmployeesAction implements Action {
|
||||
type: EmployeesActionsTypes=EmployeesActionsTypes.GET_ALL_EMPLOYEES;
|
||||
constructor(public payload:any) {
|
||||
}
|
||||
|
||||
constructor(public payload:any) {}
|
||||
}
|
||||
|
||||
export class GetAllEmployeesActionSuccess implements Action {
|
||||
type: EmployeesActionsTypes=EmployeesActionsTypes.GET_ALL_EMPLOYEES_SUCCESS;
|
||||
constructor(public payload:Employee[]) {
|
||||
}
|
||||
|
||||
constructor(public payload:Employee[]) {}
|
||||
}
|
||||
|
||||
export class GetAllEmployeesActionError implements Action {
|
||||
type: EmployeesActionsTypes=EmployeesActionsTypes.GET_ALL_EMPLOYEES_ERROR;
|
||||
constructor(public payload:string) {
|
||||
}
|
||||
|
||||
constructor(public payload:string) {}
|
||||
}
|
||||
|
||||
export type EmployeesActions=GetAllEmployeesAction | GetAllEmployeesActionSuccess | GetAllEmployeesActionError;
|
||||
export class SearchEmployeesAction implements Action {
|
||||
type: EmployeesActionsTypes=EmployeesActionsTypes.SEARCH_EMPLOYEES;
|
||||
constructor(public payload:string) {}
|
||||
}
|
||||
|
||||
export class SearchEmployeesActionSuccess implements Action {
|
||||
type: EmployeesActionsTypes=EmployeesActionsTypes.SEARCH_EMPLOYEES_SUCCESS;
|
||||
constructor(public payload:Employee[]) {}
|
||||
}
|
||||
|
||||
export class SearchEmployeesActionError implements Action {
|
||||
type: EmployeesActionsTypes=EmployeesActionsTypes.SEARCH_EMPLOYEES_ERROR;
|
||||
constructor(public payload:string) {}
|
||||
}
|
||||
|
||||
export type EmployeesActions=GetAllEmployeesAction | GetAllEmployeesActionSuccess | GetAllEmployeesActionError |
|
||||
SearchEmployeesAction | SearchEmployeesActionSuccess | SearchEmployeesActionError;
|
||||
|
||||
@@ -3,15 +3,15 @@ import { EmployeesService } from '../services/employees.service';
|
||||
import { createEffect, Actions, ofType } from '@ngrx/effects';
|
||||
import { Observable, of, EMPTY } from 'rxjs';
|
||||
import { Action } from '@ngrx/store';
|
||||
import { EmployeesActionsTypes } from './employees.actions';
|
||||
import { EmployeesActionsTypes, EmployeesActions } from './employees.actions';
|
||||
import { mergeMap, map, catchError } from 'rxjs/operators';
|
||||
import { GetAllEmployeesActionSuccess, GetAllEmployeesActionError } from './employees.actions';
|
||||
import { GetAllEmployeesActionSuccess, GetAllEmployeesActionError, SearchEmployeesActionSuccess, SearchEmployeesActionError } from './employees.actions';
|
||||
|
||||
@Injectable()
|
||||
export class EmployeesEffects {
|
||||
getAllEmployeesEffect$:Observable<Action> = createEffect(() => this.actions$.pipe(
|
||||
getAllEmployeesEffect$:Observable<EmployeesActions> = createEffect(() => this.actions$.pipe(
|
||||
ofType(EmployeesActionsTypes.GET_ALL_EMPLOYEES),
|
||||
mergeMap((action) => {
|
||||
mergeMap((action:EmployeesActions) => {
|
||||
return this.employeesService.getAllEmployees().pipe(
|
||||
map(employees => new GetAllEmployeesActionSuccess(employees)),
|
||||
catchError((err) => of(new GetAllEmployeesActionError(err.message)))
|
||||
@@ -19,6 +19,16 @@ export class EmployeesEffects {
|
||||
})
|
||||
));
|
||||
|
||||
searchEmployeesEffect$:Observable<EmployeesActions> = createEffect(() => this.actions$.pipe(
|
||||
ofType(EmployeesActionsTypes.SEARCH_EMPLOYEES),
|
||||
mergeMap((action:EmployeesActions) => {
|
||||
return this.employeesService.searchEmployees(action.payload).pipe(
|
||||
map(employees => new SearchEmployeesActionSuccess(employees)),
|
||||
catchError((err) => of(new SearchEmployeesActionError(err.message)))
|
||||
)
|
||||
})
|
||||
));
|
||||
|
||||
constructor(
|
||||
private employeesService:EmployeesService,
|
||||
private actions$:Actions
|
||||
|
||||
@@ -29,6 +29,13 @@ export function employeesReducer(state:EmployeesState=initState, action:Action):
|
||||
return {...state, dataState:EmployeesStateEnum.LOADED, employees:(<EmployeesActions>action).payload};
|
||||
case EmployeesActionsTypes.GET_ALL_EMPLOYEES_ERROR:
|
||||
return {...state, dataState:EmployeesStateEnum.ERROR, errorMessage:(<EmployeesActions>action).payload};
|
||||
/* Search Employees */
|
||||
case EmployeesActionsTypes.SEARCH_EMPLOYEES:
|
||||
return {...state, dataState:EmployeesStateEnum.LOADING};
|
||||
case EmployeesActionsTypes.SEARCH_EMPLOYEES_SUCCESS:
|
||||
return {...state, dataState:EmployeesStateEnum.LOADED, employees:(<EmployeesActions>action).payload};
|
||||
case EmployeesActionsTypes.SEARCH_EMPLOYEES_ERROR:
|
||||
return {...state, dataState:EmployeesStateEnum.ERROR, errorMessage:(<EmployeesActions>action).payload};
|
||||
default:
|
||||
return {...state}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user