Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f99b38a47 | ||
|
|
e740784f41 | ||
|
|
a6814ba5a9 | ||
|
|
2783c878c1 | ||
|
|
83d148593c | ||
|
|
12deab061d |
6
db.json
6
db.json
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"employees": [
|
||||
{
|
||||
"id": 1,
|
||||
"nom": "benoit",
|
||||
"prenom": "vincent",
|
||||
"role": "ingénieur",
|
||||
"id": 1
|
||||
"role": "ingénieur"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
@@ -19,4 +19,4 @@
|
||||
"role": "responsable"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "concurrently \"ng serve\" \"json-server --watch db.json\"",
|
||||
"start": "concurrently \"ng serve\" \"json-server -p 4000 --watch db.json\"",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
|
||||
@@ -10,6 +10,9 @@ import { EmployeesComponent } from './components/employees/employees.component';
|
||||
import { HomeComponent } from './components/home/home.component';
|
||||
import { EmployeeAddComponent } from './components/employee-add/employee-add.component';
|
||||
import { EmployeeEditComponent } from './components/employee-edit/employee-edit.component';
|
||||
import { EmployeesNavbarComponent } from './components/employees/employees-navbar/employees-navbar.component';
|
||||
import { EmployeesListComponent } from './components/employees/employees-list/employees-list.component';
|
||||
import { EmployeeItemComponent } from './components/employees/employees-list/employee-item/employee-item.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -18,7 +21,10 @@ import { EmployeeEditComponent } from './components/employee-edit/employee-edit.
|
||||
EmployeesComponent,
|
||||
HomeComponent,
|
||||
EmployeeAddComponent,
|
||||
EmployeeEditComponent
|
||||
EmployeeEditComponent,
|
||||
EmployeesNavbarComponent,
|
||||
EmployeesListComponent,
|
||||
EmployeeItemComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<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 { EmployeeItemComponent } from './employee-item.component';
|
||||
|
||||
describe('EmployeeItemComponent', () => {
|
||||
let component: EmployeeItemComponent;
|
||||
let fixture: ComponentFixture<EmployeeItemComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EmployeeItemComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EmployeeItemComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { Employee } from '../../../../model/employee.model';
|
||||
import { AppDataState, DataStateEnum, EmployeeActionsTypes, ActEvent } from '../../../../state/employee.state';
|
||||
import { EventDriverService } from '../../../../services/event.driver.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-employee-item',
|
||||
templateUrl: './employee-item.component.html',
|
||||
styleUrls: ['./employee-item.component.css']
|
||||
})
|
||||
export class EmployeeItemComponent implements OnInit {
|
||||
@Input() employee?:Employee;
|
||||
constructor(private evDrivenService:EventDriverService) { }
|
||||
|
||||
ngOnInit(): void { }
|
||||
|
||||
onDelete(val:Employee) {
|
||||
this.evDrivenService.publishEvent({
|
||||
type:EmployeeActionsTypes.DELETE_EMPLOYEE, payload:val
|
||||
});
|
||||
}
|
||||
|
||||
onEdit(val:Employee) {
|
||||
this.evDrivenService.publishEvent({
|
||||
type:EmployeeActionsTypes.EDIT_EMPLOYEE, payload:val
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<div class="container">
|
||||
<ng-container *ngIf="(employeesInput$ | async) as result" [ngSwitch]="result.dataState">
|
||||
<ng-container *ngSwitchCase="DataStateEnum.LOADING">
|
||||
Loading ...
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="DataStateEnum.ERROR">
|
||||
<div class="alert-danger">
|
||||
{{result.errorMessage}}
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="DataStateEnum.LOADED">
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>ID</th><th>Nom</th><th>Prenom</th><th>Role</th><th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<app-employee-item [employee]="p" *ngFor="let p of result.data" style="display: contents">
|
||||
</app-employee-item>
|
||||
</tbody>
|
||||
</table>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EmployeesListComponent } from './employees-list.component';
|
||||
|
||||
describe('EmployeesListComponent', () => {
|
||||
let component: EmployeesListComponent;
|
||||
let fixture: ComponentFixture<EmployeesListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EmployeesListComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EmployeesListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { AppDataState, DataStateEnum, EmployeeActionsTypes, ActEvent } from '../../../state/employee.state';
|
||||
import { Employee } from '../../../model/employee.model';
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-employees-list',
|
||||
templateUrl: './employees-list.component.html',
|
||||
styleUrls: ['./employees-list.component.css']
|
||||
})
|
||||
export class EmployeesListComponent implements OnInit {
|
||||
@Input() employeesInput$:Observable<AppDataState<Employee[]>>|null=null;
|
||||
readonly DataStateEnum=DataStateEnum;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void { }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<nav class="navbar navbar-expand-sm navbar-light bg-light">
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<button (click)="onGetAllEmployees()" class="btn btn-sm btn-outline-info ml-2">All</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button (click)="onNewEmployee()" class="btn btn-sm btn-outline-info ml-2">Ajout</button>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<form #f="ngForm" (ngSubmit)="onSearch(f.value)" class="form-inline">
|
||||
<input ngModel class="mr-sm-2" name="keyword" type="text">
|
||||
<button class="btn btn-sm btn-outline-info my-2 my-sm-0">
|
||||
<span class="fa fa-search"></span>
|
||||
</button>
|
||||
</form>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EmployeesNavbarComponent } from './employees-navbar.component';
|
||||
|
||||
describe('EmployeesNavbarComponent', () => {
|
||||
let component: EmployeesNavbarComponent;
|
||||
let fixture: ComponentFixture<EmployeesNavbarComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EmployeesNavbarComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EmployeesNavbarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { EmployeeActionsTypes, ActEvent } from '../../../state/employee.state';
|
||||
import { EventDriverService } from '../../../services/event.driver.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-employees-navbar',
|
||||
templateUrl: './employees-navbar.component.html',
|
||||
styleUrls: ['./employees-navbar.component.css']
|
||||
})
|
||||
export class EmployeesNavbarComponent implements OnInit {
|
||||
|
||||
constructor(private evDriveService:EventDriverService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
onGetAllEmployees() {
|
||||
this.evDriveService.publishEvent({type:EmployeeActionsTypes.GET_ALL_EMPLOYEES});
|
||||
}
|
||||
|
||||
onSearch(val:any) {
|
||||
this.evDriveService.publishEvent({type:EmployeeActionsTypes.SEARCH_EMPLOYEES, payload:val});
|
||||
}
|
||||
|
||||
onNewEmployee() {
|
||||
this.evDriveService.publishEvent({type:EmployeeActionsTypes.NEW_EMPLOYEE});
|
||||
}
|
||||
}
|
||||
@@ -1,57 +1,2 @@
|
||||
<nav class="navbar navbar-expand-sm navbar-light bg-light">
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<button (click)="onGetAllEmployees()" class="btn btn-sm btn-outline-info ml-2">All</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button (click)="onNewEmployee()" class="btn btn-sm btn-outline-info ml-2">Ajout</button>
|
||||
</li>
|
||||
<form #f="ngForm" (ngSubmit)="onSearch(f.value)" class="form-inline my-2 my-lg-0">
|
||||
<input ngModel class="mr-sm-2" name="keyword" type="text">
|
||||
<button class="btn btn-sm btn-outline-info my-2 my-sm-0">
|
||||
<span class="fa fa-search"></span>
|
||||
</button>
|
||||
</form>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container">
|
||||
<ng-container *ngIf="(employees$ | async) as result" [ngSwitch]="result.dataState">
|
||||
<ng-container *ngSwitchCase="DataStateEnum.LOADING">
|
||||
Loading ...
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="DataStateEnum.ERROR">
|
||||
<div class="alert-danger">
|
||||
{{result.errorMessage}}
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="DataStateEnum.LOADED">
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>ID</th><th>Nom</th><th>Prenom</th><th>Role</th><th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let p of result.data">
|
||||
<td>{{p.id}}</td>
|
||||
<td>{{p.nom}}</td>
|
||||
<td>{{p.prenom}}</td>
|
||||
<td>{{p.role}}</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-outline-danger" (click)="onDelete(p)">
|
||||
<span class="fa fa-trash"></span>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-outline-info" (click)="onEdit(p)">
|
||||
<span class="fa fa-edit"></span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
<app-employees-navbar></app-employees-navbar>
|
||||
<app-employees-list [employeesInput$]="employees$"></app-employees-list>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { EmployeesService } from '../../services/employees.service';
|
||||
import { EventDriverService } from '../../services/event.driver.service';
|
||||
import { Employee } from '../../model/employee.model';
|
||||
import { AppDataState, DataStateEnum } from '../../state/employee.state';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { AppDataState, DataStateEnum, EmployeeActionsTypes, ActEvent } from '../../state/employee.state';
|
||||
import { Observable, of, Subscription } from 'rxjs';
|
||||
import { catchError, map, startWith } from 'rxjs/operators';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@@ -11,47 +12,87 @@ import { Router } from '@angular/router';
|
||||
templateUrl: './employees.component.html',
|
||||
styleUrls: ['./employees.component.css']
|
||||
})
|
||||
export class EmployeesComponent implements OnInit {
|
||||
employees$:Observable<AppDataState<Employee[]>>|null=null;
|
||||
readonly DataStateEnum=DataStateEnum;
|
||||
export class EmployeesComponent implements OnInit, OnDestroy {
|
||||
employees$:Observable<AppDataState<Employee[]>>|null=null;
|
||||
readonly DataStateEnum=DataStateEnum;
|
||||
sub:Subscription;
|
||||
|
||||
constructor(private employeesService:EmployeesService, private router:Router) { }
|
||||
constructor(private employeesService:EmployeesService, private router:Router, private evDriveService:EventDriverService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
onGetAllEmployees() {
|
||||
this.employees$=this.employeesService.getAllEmployees().pipe(
|
||||
map(data=>{
|
||||
return ({dataState:DataStateEnum.LOADED, data:data})
|
||||
}),
|
||||
startWith({dataState:DataStateEnum.LOADING}),
|
||||
catchError(err=>of({dataState: DataStateEnum.ERROR, errorMessage:err.message}))
|
||||
);
|
||||
}
|
||||
|
||||
onSearch(val:any) {
|
||||
this.employees$=this.employeesService.searchEmployees(val.keyword).pipe(
|
||||
map(data=>{
|
||||
return ({dataState:DataStateEnum.LOADED, data:data})
|
||||
}),
|
||||
startWith({dataState:DataStateEnum.LOADING}),
|
||||
catchError(err=>of({dataState: DataStateEnum.ERROR, errorMessage:err.message}))
|
||||
);
|
||||
}
|
||||
|
||||
onDelete(val:Employee) {
|
||||
this.employeesService.deleteEmployee(val).subscribe(
|
||||
data=>{
|
||||
this.onGetAllEmployees();
|
||||
ngOnInit(): void {
|
||||
this.sub=this.evDriveService.sourceEventSubjectObservable.subscribe((actionEv:ActEvent)=>{
|
||||
this.onActionEvent(actionEv);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onNewEmployee() {
|
||||
this.router.navigateByUrl("/newEmployee");
|
||||
}
|
||||
ngOnDestroy(): void {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
onEdit(val:Employee) {
|
||||
this.router.navigateByUrl("/editEmployee/"+val.id);
|
||||
}
|
||||
onActionEvent($event: ActEvent) {
|
||||
switch($event.type) {
|
||||
case EmployeeActionsTypes.GET_ALL_EMPLOYEES: {
|
||||
this.onGetAllEmployees();
|
||||
break;
|
||||
}
|
||||
case EmployeeActionsTypes.SEARCH_EMPLOYEES: {
|
||||
this.onSearch($event.payload);
|
||||
break;
|
||||
}
|
||||
case EmployeeActionsTypes.NEW_EMPLOYEE: {
|
||||
this.onNewEmployee();
|
||||
break;
|
||||
}
|
||||
case EmployeeActionsTypes.EDIT_EMPLOYEE: {
|
||||
this.onEdit($event.payload);
|
||||
break;
|
||||
}
|
||||
case EmployeeActionsTypes.DELETE_EMPLOYEE: {
|
||||
this.onDelete($event.payload);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onGetAllEmployees() {
|
||||
this.employees$=this.employeesService.getAllEmployees().pipe(
|
||||
map(data=>{
|
||||
return ({dataState:DataStateEnum.LOADED, data:data})
|
||||
}),
|
||||
startWith({dataState:DataStateEnum.LOADING}),
|
||||
catchError(err=>of({dataState: DataStateEnum.ERROR, errorMessage:err.message}))
|
||||
);
|
||||
}
|
||||
|
||||
onSearch(val:any) {
|
||||
this.employees$=this.employeesService.searchEmployees(val.keyword).pipe(
|
||||
map(data=>{
|
||||
return ({dataState:DataStateEnum.LOADED, data:data})
|
||||
}),
|
||||
startWith({dataState:DataStateEnum.LOADING}),
|
||||
catchError(err=>of({dataState: DataStateEnum.ERROR, errorMessage:err.message}))
|
||||
);
|
||||
}
|
||||
|
||||
onDelete(val:Employee) {
|
||||
let v=confirm("Etes vous sûre?");
|
||||
if(v==true) {
|
||||
this.employeesService.deleteEmployee(val).subscribe(
|
||||
data=>{
|
||||
this.onGetAllEmployees();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onNewEmployee() {
|
||||
this.router.navigateByUrl("/newEmployee");
|
||||
}
|
||||
|
||||
onEdit(val:Employee) {
|
||||
this.router.navigateByUrl("/editEmployee/"+val.id);
|
||||
}
|
||||
}
|
||||
|
||||
13
src/app/services/event.driver.service.ts
Normal file
13
src/app/services/event.driver.service.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { ActEvent } from '../state/employee.state';
|
||||
|
||||
@Injectable({providedIn:"root"})
|
||||
export class EventDriverService {
|
||||
sourceEventSubject:Subject<ActEvent>=new Subject<ActEvent>();
|
||||
sourceEventSubjectObservable=this.sourceEventSubject.asObservable();
|
||||
|
||||
publishEvent(event:ActEvent) {
|
||||
this.sourceEventSubject.next(event);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,17 @@
|
||||
export enum EmployeeActionsTypes {
|
||||
GET_ALL_EMPLOYEES="[Employees] Get all employees",
|
||||
SEARCH_EMPLOYEES="[Employees] Search employees",
|
||||
NEW_EMPLOYEE="[Employees] New employee",
|
||||
EDIT_EMPLOYEE="[Employees] Edit employee",
|
||||
DELETE_EMPLOYEE="[Employees] Remove employee"
|
||||
}
|
||||
|
||||
export interface ActEvent {
|
||||
type:EmployeeActionsTypes,
|
||||
payload?:any,
|
||||
errMsg?:string
|
||||
}
|
||||
|
||||
export enum DataStateEnum {
|
||||
LOADING,
|
||||
LOADED,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export const environment = {
|
||||
production: true
|
||||
production: true,
|
||||
host: "http://localhost:3000"
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
host: "http://localhost:3000"
|
||||
host: "http://localhost:4000"
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"strictPropertyInitialization": false,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
|
||||
Reference in New Issue
Block a user