Merge branch 'features' into 'master'
Ajout de la génération de kits de retouche See merge request color-recipes-explorer/frontend!23
This commit is contained in:
commit
eaa63e911d
|
@ -1,6 +1,9 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {Routes, RouterModule} from '@angular/router';
|
||||
import {CatalogComponent} from "./pages/catalog/catalog.component";
|
||||
import {NgModule} from '@angular/core'
|
||||
import {Routes, RouterModule} from '@angular/router'
|
||||
import {CatalogComponent} from './pages/catalog/catalog.component'
|
||||
import {AdministrationComponent} from './pages/administration/administration.component'
|
||||
import {MiscComponent} from './pages/others/misc.component'
|
||||
import {TouchupkitComponent} from './pages/others/touchupkit/touchupkit.component'
|
||||
|
||||
|
||||
const routes: Routes = [{
|
||||
|
@ -9,39 +12,54 @@ const routes: Routes = [{
|
|||
}, {
|
||||
path: 'account',
|
||||
loadChildren: () => import('./modules/accounts/accounts.module').then(m => m.AccountsModule)
|
||||
}, {
|
||||
path: 'employee',
|
||||
loadChildren: () => import('./modules/employees/employees.module').then(m => m.EmployeesModule)
|
||||
}, {
|
||||
path: 'group',
|
||||
loadChildren: () => import('./modules/groups/groups.module').then(m => m.GroupsModule)
|
||||
}, {
|
||||
path: 'catalog',
|
||||
component: CatalogComponent,
|
||||
children: [{
|
||||
path: 'materialtype',
|
||||
loadChildren: () => import('./modules/material-type/material-type.module').then(m => m.MaterialTypeModule),
|
||||
}, {
|
||||
path: 'material',
|
||||
loadChildren: () => import('./modules/material/material.module').then(m => m.MaterialModule)
|
||||
}, {
|
||||
path: 'company',
|
||||
loadChildren: () => import('./modules/company/company.module').then(m => m.CompanyModule)
|
||||
}, {
|
||||
path: '',
|
||||
pathMatch: 'full',
|
||||
redirectTo: 'materialtype'
|
||||
}]
|
||||
}, {
|
||||
path: 'admin',
|
||||
component: AdministrationComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'materialtype',
|
||||
loadChildren: () => import('./modules/material-type/material-type.module').then(m => m.MaterialTypeModule),
|
||||
},
|
||||
{
|
||||
path: 'material',
|
||||
loadChildren: () => import('./modules/material/material.module').then(m => m.MaterialModule)
|
||||
},
|
||||
{
|
||||
path: 'company',
|
||||
loadChildren: () => import('./modules/company/company.module').then(m => m.CompanyModule)
|
||||
},
|
||||
{
|
||||
path: 'user',
|
||||
loadChildren: () => import('./modules/users/user.module').then(m => m.UserModule)
|
||||
}, {
|
||||
path: 'group',
|
||||
loadChildren: () => import('./modules/groups/group.module').then(m => m.GroupModule)
|
||||
}, {
|
||||
path: '',
|
||||
pathMatch: 'full',
|
||||
redirectTo: 'materialtype'
|
||||
redirectTo: 'user'
|
||||
}
|
||||
]
|
||||
},
|
||||
{path: 'material', loadChildren: () => import('./modules/material/material.module').then(m => m.MaterialModule)}];
|
||||
}, {
|
||||
path: 'misc',
|
||||
component: MiscComponent,
|
||||
children: [{
|
||||
path: 'touchupkit',
|
||||
component: TouchupkitComponent
|
||||
}, {
|
||||
path: '',
|
||||
pathMatch: 'full',
|
||||
redirectTo: 'touchupkit'
|
||||
}]
|
||||
}]
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
|
||||
imports: [RouterModule.forRoot(routes, {relativeLinkResolution: 'legacy'})],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule {
|
||||
|
|
|
@ -8,11 +8,17 @@ import {SharedModule} from "./modules/shared/shared.module";
|
|||
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||
import {CatalogComponent} from './pages/catalog/catalog.component';
|
||||
import {CompanyModule} from './modules/company/company.module';
|
||||
import { AdministrationComponent } from './pages/administration/administration.component';
|
||||
import { MiscComponent } from './pages/others/misc.component';
|
||||
import { TouchupkitComponent } from './pages/others/touchupkit/touchupkit.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
CatalogComponent
|
||||
CatalogComponent,
|
||||
AdministrationComponent,
|
||||
MiscComponent,
|
||||
TouchupkitComponent
|
||||
],
|
||||
imports: [
|
||||
AppRoutingModule,
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<mat-form-field>
|
||||
<mat-label>Numéro d'employé</mat-label>
|
||||
<mat-label>Numéro d'utilisateur</mat-label>
|
||||
<input matInput [formControl]="idFormControl" type="text"/>
|
||||
<mat-icon matSuffix>person</mat-icon>
|
||||
<mat-error *ngIf="idFormControl.invalid">
|
||||
<span *ngIf="idFormControl.errors.required">Un numéro d'employé est requis</span>
|
||||
<span *ngIf="idFormControl.errors.pattern">Le numéro d'employé doit être un nombre</span>
|
||||
<span *ngIf="idFormControl.errors.required">Un numéro d'utilisateur est requis</span>
|
||||
<span *ngIf="idFormControl.errors.pattern">Le numéro d'utilisateur doit être un nombre</span>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {NgModule} from '@angular/core'
|
||||
|
||||
import {ColorsRoutingModule} from './colors-routing.module';
|
||||
import {SharedModule} from "../shared/shared.module";
|
||||
import {ListComponent} from './pages/list/list.component';
|
||||
import {AddComponent} from './pages/add/add.component';
|
||||
import {EditComponent} from './pages/edit/edit.component';
|
||||
import {MatExpansionModule} from "@angular/material/expansion";
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import {ExploreComponent} from './pages/explore/explore.component';
|
||||
import {RecipeInfoComponent} from './components/recipe-info/recipe-info.component';
|
||||
import {MixTableComponent} from './components/mix-table/mix-table.component';
|
||||
import {StepListComponent} from './components/step-list/step-list.component';
|
||||
import {StepTableComponent} from './components/step-table/step-table.component';
|
||||
import {MixEditorComponent} from './components/mix-editor/mix-editor.component';
|
||||
import {UnitSelectorComponent} from './components/unit-selector/unit-selector.component';
|
||||
import {MixAddComponent} from './pages/mix/mix-add/mix-add.component';
|
||||
import {MixEditComponent} from './pages/mix/mix-edit/mix-edit.component';
|
||||
import { ImagesEditorComponent } from './components/images-editor/images-editor.component';
|
||||
import { MixesCardComponent } from './components/mixes-card/mixes-card.component';
|
||||
import {ColorsRoutingModule} from './colors-routing.module'
|
||||
import {SharedModule} from '../shared/shared.module'
|
||||
import {ListComponent} from './pages/list/list.component'
|
||||
import {AddComponent} from './pages/add/add.component'
|
||||
import {EditComponent} from './pages/edit/edit.component'
|
||||
import {MatExpansionModule} from '@angular/material/expansion'
|
||||
import {FormsModule} from '@angular/forms'
|
||||
import {ExploreComponent} from './pages/explore/explore.component'
|
||||
import {RecipeInfoComponent} from './components/recipe-info/recipe-info.component'
|
||||
import {MixTableComponent} from './components/mix-table/mix-table.component'
|
||||
import {StepListComponent} from './components/step-list/step-list.component'
|
||||
import {StepTableComponent} from './components/step-table/step-table.component'
|
||||
import {MixEditorComponent} from './components/mix-editor/mix-editor.component'
|
||||
import {UnitSelectorComponent} from './components/unit-selector/unit-selector.component'
|
||||
import {MixAddComponent} from './pages/mix/mix-add/mix-add.component'
|
||||
import {MixEditComponent} from './pages/mix/mix-edit/mix-edit.component'
|
||||
import {ImagesEditorComponent} from './components/images-editor/images-editor.component'
|
||||
import {MixesCardComponent} from './components/mixes-card/mixes-card.component'
|
||||
import {MatSortModule} from '@angular/material/sort'
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [ListComponent, AddComponent, EditComponent, ExploreComponent, RecipeInfoComponent, MixTableComponent, StepListComponent, StepTableComponent, MixEditorComponent, UnitSelectorComponent, MixAddComponent, MixEditComponent, ImagesEditorComponent, MixesCardComponent],
|
||||
exports: [
|
||||
UnitSelectorComponent
|
||||
],
|
||||
imports: [
|
||||
ColorsRoutingModule,
|
||||
SharedModule,
|
||||
MatExpansionModule,
|
||||
FormsModule,
|
||||
MatSortModule
|
||||
]
|
||||
declarations: [ListComponent, AddComponent, EditComponent, ExploreComponent, RecipeInfoComponent, MixTableComponent, StepListComponent, StepTableComponent, MixEditorComponent, UnitSelectorComponent, MixAddComponent, MixEditComponent, ImagesEditorComponent, MixesCardComponent],
|
||||
exports: [
|
||||
UnitSelectorComponent
|
||||
],
|
||||
imports: [
|
||||
ColorsRoutingModule,
|
||||
SharedModule,
|
||||
MatExpansionModule,
|
||||
FormsModule,
|
||||
MatSortModule
|
||||
]
|
||||
})
|
||||
export class ColorsModule {
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<mat-card *ngIf="editionMode || hasImages">
|
||||
<mat-card *ngIf="editionMode || imagesUrls">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Images</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content [class.no-action]="!editionMode">
|
||||
<div class="d-flex flex-row justify-content-around flex-wrap">
|
||||
<div *ngFor="let imageId of (imageIds$ | async)" class="d-flex flex-column align-self-center m-3">
|
||||
<div *ngFor="let imageUrl of imagesUrls" class="d-flex flex-column align-self-center m-3">
|
||||
<div class="image-wrapper">
|
||||
<img src="{{backendUrl}}/recipe/{{recipe.id}}/image/{{imageId}}" width="300px"/>
|
||||
<img [src]="imageUrl" width="300px"/>
|
||||
<div class="d-flex flex-row justify-content-end mt-2" [class.justify-content-between]="editionMode">
|
||||
<button mat-raised-button color="primary" (click)="openImage(imageId)">Afficher</button>
|
||||
<button *ngIf="editionMode" mat-raised-button color="warn" (click)="delete(imageId)">Retirer</button>
|
||||
<button mat-raised-button color="primary" (click)="openImage(imageUrl)">Afficher</button>
|
||||
<button *ngIf="editionMode" mat-raised-button color="warn" (click)="delete(imageUrl)">Retirer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,11 +2,9 @@ import {Component, Input} from '@angular/core'
|
|||
import {Recipe} from '../../../shared/model/recipe.model'
|
||||
import {SubscribingComponent} from '../../../shared/components/subscribing.component'
|
||||
import {ActivatedRoute, Router} from '@angular/router'
|
||||
import {Observable} from 'rxjs'
|
||||
import {RecipeImageService} from '../../services/recipe-image.service'
|
||||
import {environment} from '../../../../../environments/environment'
|
||||
import {ErrorService} from '../../../shared/service/error.service'
|
||||
import {globalLoadingWheel} from '../../../shared/components/loading-wheel/loading-wheel.component'
|
||||
import {openJpg} from '../../../shared/utils/utils'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-images-editor',
|
||||
|
@ -17,9 +15,7 @@ export class ImagesEditorComponent extends SubscribingComponent {
|
|||
@Input() recipe: Recipe
|
||||
@Input() editionMode = false
|
||||
|
||||
imageIds$: Observable<number[]>
|
||||
backendUrl = environment.apiUrl
|
||||
hasImages = false
|
||||
imagesUrls: string[]
|
||||
|
||||
constructor(
|
||||
private recipeImageService: RecipeImageService,
|
||||
|
@ -33,35 +29,29 @@ export class ImagesEditorComponent extends SubscribingComponent {
|
|||
ngOnInit() {
|
||||
super.ngOnInit()
|
||||
|
||||
this.loadImagesIds()
|
||||
this.subscribe(
|
||||
this.imageIds$,
|
||||
ids => this.hasImages = ids.length > 0,
|
||||
false,
|
||||
1
|
||||
)
|
||||
this.imagesUrls = this.recipe.imagesUrls
|
||||
}
|
||||
|
||||
submit(event) {
|
||||
const image = event.target.files[0]
|
||||
this.subscribe(
|
||||
this.recipeImageService.save(image, this.recipe.id),
|
||||
() => this.loadImagesIds()
|
||||
r => this.imagesUrls = r.imagesUrls
|
||||
)
|
||||
}
|
||||
|
||||
openImage(imageId: number) {
|
||||
window.open(`${environment.apiUrl}/recipe/${this.recipe.id}/image/${imageId}`, '_blank')
|
||||
openImage(url: string) {
|
||||
openJpg(url)
|
||||
}
|
||||
|
||||
delete(imageId: number) {
|
||||
delete(url: string) {
|
||||
this.subscribe(
|
||||
this.recipeImageService.delete(imageId, this.recipe.id),
|
||||
() => this.loadImagesIds()
|
||||
this.recipeImageService.delete(url, this.recipe.id),
|
||||
() => this.removeUrl(url)
|
||||
)
|
||||
}
|
||||
|
||||
private loadImagesIds() {
|
||||
this.imageIds$ = this.recipeImageService.getAllIdsForRecipe(this.recipe.id)
|
||||
private removeUrl(url: string) {
|
||||
this.imagesUrls = this.imagesUrls.filter(u => u !== url)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,8 +126,8 @@
|
|||
<button
|
||||
mat-raised-button
|
||||
color="accent"
|
||||
[disabled]="!hasSimdutMap[getMixMaterialFromDto(mixMaterial).material.id]"
|
||||
(click)="openSimdutFile(mixMaterial)">
|
||||
[disabled]="!hasSimdut(getMixMaterialFromDto(mixMaterial).material)"
|
||||
(click)="openSimdut(mixMaterial)">
|
||||
Fiche signalitique
|
||||
</button>
|
||||
</ng-container>
|
||||
|
|
|
@ -12,6 +12,7 @@ import {environment} from '../../../../../environments/environment'
|
|||
import {MaterialService} from '../../../material/service/material.service'
|
||||
import {EmployeePermission} from '../../../shared/model/employee'
|
||||
import {AccountService} from '../../../accounts/services/account.service'
|
||||
import {Material, openSimdut} from '../../../shared/model/material.model'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-mix-table',
|
||||
|
@ -38,7 +39,6 @@ export class MixTableComponent extends SubscribingComponent {
|
|||
units = UNIT_MILLILITER
|
||||
mixMaterials: MixMaterialDto[] = []
|
||||
hoveredMixMaterial: MixMaterial | null
|
||||
hasSimdutMap: any = {}
|
||||
|
||||
// BPac printer
|
||||
printer: PtouchPrinter | null
|
||||
|
@ -67,12 +67,14 @@ export class MixTableComponent extends SubscribingComponent {
|
|||
this.units$,
|
||||
u => this.convertQuantities(u)
|
||||
)
|
||||
}
|
||||
|
||||
this.mixMaterials.forEach(mixMaterial => this.subscribe(
|
||||
this.materialService.hasSimdut(mixMaterial.materialId),
|
||||
b => this.hasSimdutMap[mixMaterial.materialId] = b
|
||||
)
|
||||
)
|
||||
hasSimdut(material: Material): boolean {
|
||||
return material.simdutUrl != null
|
||||
}
|
||||
|
||||
openSimdut(mixMaterial: MixMaterial) {
|
||||
openSimdut(mixMaterial.material)
|
||||
}
|
||||
|
||||
changeLocation(event: any) {
|
||||
|
@ -135,10 +137,6 @@ export class MixTableComponent extends SubscribingComponent {
|
|||
return Math.round(quantity * 1000) / 1000
|
||||
}
|
||||
|
||||
openSimdutFile(mixMaterial: MixMaterialDto) {
|
||||
window.open(`${environment.apiUrl}/material/${mixMaterial.materialId}/simdut`, '_blank')
|
||||
}
|
||||
|
||||
async print() {
|
||||
const base = this.mix.mixMaterials
|
||||
.map(ma => ma.material)
|
||||
|
|
|
@ -73,8 +73,8 @@
|
|||
</div>
|
||||
|
||||
<!-- Images -->
|
||||
<div [hidden]="!images.hasImages">
|
||||
<cre-images-editor #images [recipe]="recipe" [editionMode]="false"></cre-images-editor>
|
||||
<div *ngIf="recipe.imagesUrls">
|
||||
<cre-images-editor [recipe]="recipe" [editionMode]="false"></cre-images-editor>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
*ngIf="isRecipeApprobationExpired(recipe)"
|
||||
svgIcon="clock-alert"
|
||||
class="color-warning"
|
||||
title="L'approbation de cette recette est expirée (il y a plus de 4 ans)">
|
||||
title="L'approbation de l'échantillon est expirée (il y a plus de 4 ans)">
|
||||
</mat-icon>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {ApiService} from "../../shared/service/api.service";
|
||||
import {Observable} from "rxjs";
|
||||
import {Injectable} from '@angular/core'
|
||||
import {ApiService} from '../../shared/service/api.service'
|
||||
import {Observable} from 'rxjs'
|
||||
import {Recipe} from '../../shared/model/recipe.model'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -11,22 +12,17 @@ export class RecipeImageService {
|
|||
) {
|
||||
}
|
||||
|
||||
getAllIdsForRecipe(recipeId: number): Observable<number[]> {
|
||||
return this.api.get(`/recipe/${recipeId}/image`)
|
||||
}
|
||||
|
||||
save(image: File, recipeId: number): Observable<void> {
|
||||
save(image: File, recipeId: number): Observable<Recipe> {
|
||||
const body = new FormData()
|
||||
body.append('image', image)
|
||||
return this.api.post<void>(`/recipe/${recipeId}/image`, body, true)
|
||||
return this.api.put<Recipe>(`/recipe/${recipeId}/image`, body)
|
||||
}
|
||||
|
||||
deleteAll(imageIds: number[], recipeId: number) {
|
||||
imageIds.forEach(id => this.delete(id, recipeId))
|
||||
}
|
||||
delete(url: string, recipeId: number): Observable<void> {
|
||||
const urlFragments = url.split('%2F')
|
||||
const imageName = urlFragments[urlFragments.length - 1].replace('.jpg', '')
|
||||
|
||||
delete(imageId: number, recipeId: number): Observable<void> {
|
||||
return this.api.delete<void>(`/recipe/${recipeId}/image/${imageId}`)
|
||||
return this.api.delete<void>(`/recipe/${recipeId}/image/${imageName}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { ListComponent } from './pages/list/list.component';
|
||||
import {AddComponent} from "./pages/add/add.component";
|
||||
import {EditComponent} from "./pages/edit/edit.component";
|
||||
import {PasswordEditComponent} from "./pages/password-edit/password-edit.component";
|
||||
|
||||
const routes: Routes = [{ path: 'list', component: ListComponent }, {path: 'add', component: AddComponent}, {path: 'edit/:id', component: EditComponent}, {path: 'password/edit/:id', component: PasswordEditComponent}, {path: '', redirectTo: 'list'}];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class EmployeesRoutingModule { }
|
|
@ -1,34 +0,0 @@
|
|||
<ng-container *ngIf="employees$ | async as employees">
|
||||
<table class="my-3 mx-auto mat-elevation-z1" *ngIf="employees.length > 0" mat-table [dataSource]="employees">
|
||||
<ng-container matColumnDef="id">
|
||||
<th mat-header-cell *matHeaderCellDef>Numéro d'employé</th>
|
||||
<td mat-cell *matCellDef="let employee">{{employee.id}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="firstName">
|
||||
<th mat-header-cell *matHeaderCellDef>Prénom</th>
|
||||
<td mat-cell *matCellDef="let employee">{{employee.firstName}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="lastName">
|
||||
<th mat-header-cell *matHeaderCellDef>Nom</th>
|
||||
<td mat-cell *matCellDef="let employee">{{employee.lastName}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="edit">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell [class.disabled]="!canEditEmployee" *matCellDef="let employee">
|
||||
<button mat-raised-button color="accent">Modifier</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="columns"></tr>
|
||||
<tr mat-row *matRowDef="let employee; columns: columns"></tr>
|
||||
<tr>
|
||||
<td>test</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<ng-container *ngIf="employees.length <= 0">
|
||||
<div class="w-100 mt-2 text-center empty">
|
||||
<p>Il n'y a aucun employé dans ce groupe</p>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
|
@ -1,2 +0,0 @@
|
|||
.d-flex
|
||||
gap: 2rem
|
|
@ -1,31 +0,0 @@
|
|||
import {Component, Input, OnInit} from '@angular/core'
|
||||
import {Employee, EmployeeGroup, EmployeePermission} from '../../../shared/model/employee'
|
||||
import {GroupService} from '../../services/group.service'
|
||||
import {AccountService} from '../../../accounts/services/account.service'
|
||||
import {Observable} from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-employees-list',
|
||||
templateUrl: './employees-list.component.html',
|
||||
styleUrls: ['./employees-list.component.sass']
|
||||
})
|
||||
export class EmployeesListComponent implements OnInit {
|
||||
@Input() group: EmployeeGroup
|
||||
|
||||
employees$: Observable<Employee[]> | null
|
||||
columns = ['id', 'firstName', 'lastName', 'edit']
|
||||
|
||||
constructor(
|
||||
private accountService: AccountService,
|
||||
private groupService: GroupService
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.employees$ = this.groupService.getEmployeesForGroup(this.group.id)
|
||||
}
|
||||
|
||||
get canEditEmployee(): boolean {
|
||||
return this.accountService.hasPermission(EmployeePermission.EDIT_USERS)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import {NgModule} from '@angular/core'
|
||||
import {RouterModule, Routes} from '@angular/router'
|
||||
|
||||
import {ListComponent} from './pages/list/list.component'
|
||||
import {AddComponent} from './pages/add/add.component'
|
||||
import {EditComponent} from './pages/edit/edit.component'
|
||||
|
||||
const routes: Routes = [{
|
||||
path: 'list', component: ListComponent
|
||||
}, {
|
||||
path: 'add', component: AddComponent
|
||||
}, {
|
||||
path: 'edit/:id', component: EditComponent
|
||||
}, {
|
||||
path: '', redirectTo: 'list'
|
||||
}]
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class GroupRoutingModule {
|
||||
}
|
|
@ -1,18 +1,17 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
|
||||
import {GroupsRoutingModule} from './groups-routing.module';
|
||||
import {GroupRoutingModule} from './group-routing.module';
|
||||
import {ListComponent} from './pages/list/list.component';
|
||||
import {SharedModule} from "../shared/shared.module";
|
||||
import {AddComponent} from './pages/add/add.component';
|
||||
import {EditComponent} from './pages/edit/edit.component';
|
||||
import {EmployeesListComponent} from './components/employees-list/employees-list.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [ListComponent, AddComponent, EditComponent, EmployeesListComponent],
|
||||
declarations: [ListComponent, AddComponent, EditComponent],
|
||||
imports: [
|
||||
GroupsRoutingModule,
|
||||
GroupRoutingModule,
|
||||
SharedModule
|
||||
]
|
||||
})
|
||||
export class GroupsModule { }
|
||||
export class GroupModule { }
|
|
@ -1,15 +0,0 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
|
||||
import {ListComponent} from './pages/list/list.component';
|
||||
import {AddComponent} from "./pages/add/add.component";
|
||||
import {EditComponent} from "./pages/edit/edit.component";
|
||||
|
||||
const routes: Routes = [{path: 'list', component: ListComponent}, {path: 'add', component: AddComponent}, {path: 'edit/:id', component: EditComponent}, {path: '', redirectTo: 'list'}];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class GroupsRoutingModule {
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<cre-entity-add
|
||||
title="Création d'un groupe"
|
||||
backButtonLink="/group/list"
|
||||
backButtonLink="/admin/group/list"
|
||||
[formFields]="formFields"
|
||||
(submit)="submit($event)">
|
||||
</cre-entity-add>
|
||||
|
|
|
@ -57,7 +57,7 @@ export class AddComponent extends ErrorHandlingComponent {
|
|||
if (permissionsField.valid()) {
|
||||
this.subscribeAndNavigate(
|
||||
this.groupService.save(values.name, permissionsField.allEnabledPermissions),
|
||||
'/group/list'
|
||||
'/admin/group/list'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<cre-entity-edit
|
||||
*ngIf="group"
|
||||
title="Modifier le groupe {{group.name}}"
|
||||
backButtonLink="/group/list"
|
||||
backButtonLink="/admin/group/list"
|
||||
deletePermission="REMOVE_USERS"
|
||||
deleteConfirmMessage="Voulez-vous vraiment supprimer le groupe {{group.name}}?"
|
||||
[entity]="group"
|
||||
|
|
|
@ -37,7 +37,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
|
||||
errorHandlers: ErrorHandler[] = [{
|
||||
filter: error => error.type === 'notfound-employeegroup-id',
|
||||
consumer: error => this.urlUtils.navigateTo('/group/list')
|
||||
consumer: error => this.urlUtils.navigateTo('/admin/group/list')
|
||||
}, {
|
||||
filter: error => error.type === 'exists-employeegroup-name',
|
||||
messageProducer: error => `Un groupe avec le nom '${error.name}' existe déjà`
|
||||
|
@ -69,7 +69,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
if (permissionsField.valid()) {
|
||||
this.subscribeAndNavigate(
|
||||
this.groupService.update(this.group.id, values.name, permissionsField.allEnabledPermissions),
|
||||
'/group/list'
|
||||
'/admin/group/list'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
delete() {
|
||||
this.subscribeAndNavigate(
|
||||
this.groupService.delete(this.group.id),
|
||||
'/group/list'
|
||||
'/admin/group/list'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<cre-entity-list
|
||||
addLink="/group/add"
|
||||
addLink="/admin/group/add"
|
||||
addPermission="EDIT_USERS"
|
||||
[entities$]="groups$"
|
||||
[columns]="columns"
|
||||
|
|
|
@ -25,7 +25,7 @@ export class ListComponent extends ErrorHandlingComponent {
|
|||
disabledFn: group => this.isDefaultGroup(group)
|
||||
}, {
|
||||
text: 'Modifier',
|
||||
linkFn: group => `/group/edit/${group.id}`,
|
||||
linkFn: group => `/admin/group/edit/${group.id}`,
|
||||
permission: EmployeePermission.EDIT_USERS
|
||||
}]
|
||||
|
||||
|
|
|
@ -1,28 +1,23 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {ListComponent} from "./pages/list/list.component";
|
||||
import {AddComponent} from "./pages/add/add.component";
|
||||
import {EditComponent} from "./pages/edit/edit.component";
|
||||
import {NgModule} from '@angular/core'
|
||||
import {RouterModule, Routes} from '@angular/router'
|
||||
import {ListComponent} from './pages/list/list.component'
|
||||
import {AddComponent} from './pages/add/add.component'
|
||||
import {EditComponent} from './pages/edit/edit.component'
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'list',
|
||||
component: ListComponent
|
||||
},
|
||||
{
|
||||
path: 'add',
|
||||
component: AddComponent
|
||||
},
|
||||
{
|
||||
path: 'edit/:id',
|
||||
component: EditComponent
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'list'
|
||||
}
|
||||
];
|
||||
const routes: Routes = [{
|
||||
path: 'list',
|
||||
component: ListComponent
|
||||
}, {
|
||||
path: 'add',
|
||||
component: AddComponent
|
||||
}, {
|
||||
path: 'edit/:id',
|
||||
component: EditComponent
|
||||
}, {
|
||||
path: '',
|
||||
redirectTo: 'list'
|
||||
}]
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
color="primary"
|
||||
[disabled]="!hasSimdut"
|
||||
[attr.title]="!hasSimdut ? 'Ce produit n\'a pas de fiche signalitique' : null"
|
||||
(click)="openSimdutUrl()">
|
||||
(click)="openSimdut()">
|
||||
Voir la fiche signalitique
|
||||
</button>
|
||||
<cre-file-button
|
||||
|
|
|
@ -6,8 +6,7 @@ import {MaterialTypeService} from '../../../material-type/service/material-type.
|
|||
import {MaterialService} from '../../service/material.service'
|
||||
import {ActivatedRoute, Router} from '@angular/router'
|
||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||
import {Material} from '../../../shared/model/material.model'
|
||||
import {environment} from '../../../../../environments/environment'
|
||||
import {Material, openSimdut} from '../../../shared/model/material.model'
|
||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||
|
||||
@Component({
|
||||
|
@ -65,7 +64,6 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
fileType: 'application/pdf'
|
||||
}
|
||||
]
|
||||
hasSimdut = false
|
||||
selectedSimdutFile: File | null
|
||||
|
||||
errorHandlers: ErrorHandler[] = [{
|
||||
|
@ -100,11 +98,6 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
id,
|
||||
material => this.material = material
|
||||
)
|
||||
|
||||
this.subscribe(
|
||||
this.materialService.hasSimdut(id),
|
||||
b => this.hasSimdut = b
|
||||
)
|
||||
}
|
||||
|
||||
submit(values) {
|
||||
|
@ -121,8 +114,11 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
)
|
||||
}
|
||||
|
||||
openSimdutUrl() {
|
||||
const simdutUrl = environment.apiUrl + `/material/${this.material.id}/simdut`
|
||||
window.open(simdutUrl, '_blank')
|
||||
get hasSimdut(): boolean {
|
||||
return this.material.simdutUrl != null
|
||||
}
|
||||
|
||||
openSimdut() {
|
||||
openSimdut(this.material)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,13 @@ import {MaterialService} from '../../service/material.service'
|
|||
import {EmployeePermission} from '../../../shared/model/employee'
|
||||
import {ActivatedRoute, Router} from '@angular/router'
|
||||
import {ErrorService} from '../../../shared/service/error.service'
|
||||
import {Material} from '../../../shared/model/material.model'
|
||||
import {Material, openSimdut} from '../../../shared/model/material.model'
|
||||
import {AccountService} from '../../../accounts/services/account.service'
|
||||
import {convertQuantity, UNIT_MILLILITER} from '../../../shared/units'
|
||||
import {MatSort} from '@angular/material/sort'
|
||||
import {MatTableDataSource} from '@angular/material/table'
|
||||
import {MaterialTypeService} from '../../../material-type/service/material-type.service'
|
||||
import {InventoryService} from '../../service/inventory.service'
|
||||
import {environment} from '../../../../../environments/environment'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-list',
|
||||
|
@ -24,7 +23,6 @@ export class InventoryComponent extends ErrorHandlingComponent {
|
|||
materials: Material[] | null
|
||||
materialTypes$ = this.materialTypeService.all
|
||||
dataSource: MatTableDataSource<Material>
|
||||
hasSimdut: any
|
||||
|
||||
columns = ['name', 'materialType', 'quantity', 'addQuantity', 'lowQuantityIcon', 'simdutIcon', 'editButton', 'openSimdutButton']
|
||||
hoveredMaterial: Material | null
|
||||
|
@ -59,13 +57,6 @@ export class InventoryComponent extends ErrorHandlingComponent {
|
|||
true,
|
||||
1
|
||||
)
|
||||
|
||||
this.subscribe(
|
||||
this.materialService.getSimduts(),
|
||||
ids => this.hasSimdut = ids,
|
||||
false,
|
||||
1
|
||||
)
|
||||
}
|
||||
|
||||
setupDataSource(): MatTableDataSource<Material> {
|
||||
|
@ -102,11 +93,11 @@ export class InventoryComponent extends ErrorHandlingComponent {
|
|||
}
|
||||
|
||||
materialHasSimdut(material: Material): boolean {
|
||||
return this.hasSimdut && this.hasSimdut.filter(i => i === material.id).length > 0
|
||||
return material.simdutUrl != null
|
||||
}
|
||||
|
||||
openSimdut(material: Material) {
|
||||
window.open(`${environment.apiUrl}/material/${material.id}/simdut`, '_blank')
|
||||
openSimdut(material)
|
||||
}
|
||||
|
||||
addQuantity(material: Material, input: HTMLInputElement) {
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
<div *ngIf="employee" class="employee-info-container d-flex flex-column">
|
||||
<labeled-icon *ngIf="authenticated" icon="account" label="{{employee.firstName}} {{employee.lastName}}"></labeled-icon>
|
||||
<div class="d-flex flex-row">
|
||||
<labeled-icon *ngIf="authenticated" icon="pound" [label]="employee.id.toString()"></labeled-icon>
|
||||
<labeled-icon *ngIf="employeeInGroup" class="employee-info-group" icon="account-multiple" [label]="employee.group.name"></labeled-icon>
|
||||
</div>
|
||||
</div>
|
|
@ -1,12 +0,0 @@
|
|||
@import "../../../../../custom-theme"
|
||||
|
||||
p, labeled-icon
|
||||
margin: 0
|
||||
color: $light-primary-text
|
||||
|
||||
.employee-info-container
|
||||
margin-top: .85rem
|
||||
margin-right: 1rem
|
||||
|
||||
.employee-info-group
|
||||
margin-left: 0.7rem
|
|
@ -1,45 +0,0 @@
|
|||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {AppState} from "../../app-state";
|
||||
import {Employee} from "../../model/employee";
|
||||
import {Subject} from "rxjs";
|
||||
import {takeUntil} from "rxjs/operators";
|
||||
|
||||
@Component({
|
||||
selector: 'cre-employee-info',
|
||||
templateUrl: './employee-info.component.html',
|
||||
styleUrls: ['./employee-info.component.sass']
|
||||
})
|
||||
export class EmployeeInfoComponent implements OnInit, OnDestroy {
|
||||
authenticated = false
|
||||
employee: Employee = null
|
||||
employeeInGroup = false
|
||||
|
||||
private destroy$ = new Subject<boolean>()
|
||||
|
||||
constructor(
|
||||
public appState: AppState
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.authenticationState(this.appState.isAuthenticated, this.appState.authenticatedEmployee)
|
||||
this.appState.authenticatedUser$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: authentication => this.authenticationState(authentication.authenticated, authentication.authenticatedUser)
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next(true)
|
||||
this.destroy$.complete()
|
||||
}
|
||||
|
||||
private authenticationState(authenticated: boolean, employee: Employee) {
|
||||
this.authenticated = authenticated
|
||||
this.employee = employee
|
||||
if (this.employee != null) {
|
||||
this.employeeInGroup = this.employee.group != null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<div class="employee-menu-wrapper">
|
||||
<div *ngIf="employee" class="employee-info-wrapper d-flex flex-column" (click)="menuEnabled = !menuEnabled">
|
||||
<labeled-icon
|
||||
*ngIf="authenticated"
|
||||
icon="account"
|
||||
label="{{employee.firstName}} {{employee.lastName}}">
|
||||
</labeled-icon>
|
||||
<div class="d-flex flex-row">
|
||||
<labeled-icon
|
||||
*ngIf="authenticated"
|
||||
icon="pound"
|
||||
[label]="employee.id.toString()">
|
||||
</labeled-icon>
|
||||
<labeled-icon
|
||||
*ngIf="employeeInGroup"
|
||||
class="employee-info-group"
|
||||
icon="account-multiple"
|
||||
[label]="employee.group.name">
|
||||
</labeled-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
*ngIf="!authenticated && !employeeInGroup"
|
||||
(click)="openLogout()">
|
||||
Connexion
|
||||
</button>
|
||||
|
||||
<mat-action-list *ngIf="menuEnabled">
|
||||
<button
|
||||
*ngIf="!authenticated && employeeInGroup"
|
||||
mat-list-item
|
||||
class="employee-menu-item-login"
|
||||
(click)="openLogin()">
|
||||
Connexion
|
||||
</button>
|
||||
<button
|
||||
*ngIf="authenticated"
|
||||
mat-list-item
|
||||
class="employee-menu-item-logout"
|
||||
(click)="openLogout()">
|
||||
Déconnexion
|
||||
</button>
|
||||
</mat-action-list>
|
||||
</div>
|
|
@ -0,0 +1,38 @@
|
|||
@import "../../../../../custom-theme"
|
||||
|
||||
p, labeled-icon
|
||||
margin: 0
|
||||
color: $light-primary-text
|
||||
|
||||
.employee-info-wrapper
|
||||
margin: 1rem 1rem 0
|
||||
cursor: pointer
|
||||
|
||||
&:hover labeled-icon
|
||||
text-decoration: underline
|
||||
|
||||
.employee-info-group
|
||||
margin-left: 0.7rem
|
||||
|
||||
mat-action-list
|
||||
position: absolute
|
||||
transform: translateY(-2px)
|
||||
z-index: 91
|
||||
|
||||
button
|
||||
background-color: $color-primary !important
|
||||
color: $light-primary-text !important
|
||||
|
||||
&:hover
|
||||
background-color: $color-primary !important
|
||||
text-decoration: underline
|
||||
|
||||
&:not(.mat-list-item)
|
||||
font-size: 16px
|
||||
font-weight: 400
|
||||
line-height: 24px
|
||||
margin-top: 16px
|
||||
padding-left: 16px
|
||||
padding-right: 16px
|
||||
height: 48px
|
||||
border: none
|
|
@ -0,0 +1,62 @@
|
|||
import {Component, OnDestroy, OnInit} from '@angular/core'
|
||||
import {AppState} from '../../app-state'
|
||||
import {Employee} from '../../model/employee'
|
||||
import {Subject} from 'rxjs'
|
||||
import {takeUntil} from 'rxjs/operators'
|
||||
import {UrlUtils} from '../../utils/url.utils'
|
||||
import {ActivatedRoute, Router} from '@angular/router'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-employee-menu',
|
||||
templateUrl: './employee-menu.component.html',
|
||||
styleUrls: ['./employee-menu.component.sass']
|
||||
})
|
||||
export class EmployeeMenuComponent implements OnInit, OnDestroy {
|
||||
authenticated = false
|
||||
employee: Employee = null
|
||||
employeeInGroup = false
|
||||
menuEnabled = false
|
||||
|
||||
private destroy$ = new Subject<boolean>()
|
||||
private urlUtils: UrlUtils
|
||||
|
||||
constructor(
|
||||
private appState: AppState,
|
||||
private router: Router,
|
||||
private activatedRoute: ActivatedRoute
|
||||
) {
|
||||
this.urlUtils = new UrlUtils(activatedRoute, router)
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.authenticationState(this.appState.isAuthenticated, this.appState.authenticatedEmployee)
|
||||
this.appState.authenticatedUser$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: authentication => this.authenticationState(authentication.authenticated, authentication.authenticatedUser)
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next(true)
|
||||
this.destroy$.complete()
|
||||
}
|
||||
|
||||
openLogin() {
|
||||
this.urlUtils.navigateTo('/account/login')
|
||||
this.menuEnabled = false
|
||||
}
|
||||
|
||||
openLogout() {
|
||||
this.urlUtils.navigateTo('/account/logout')
|
||||
this.menuEnabled = false
|
||||
}
|
||||
|
||||
private authenticationState(authenticated: boolean, employee: Employee) {
|
||||
this.authenticated = authenticated
|
||||
this.employee = employee
|
||||
if (this.employee != null) {
|
||||
this.employeeInGroup = this.employee.group != null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
</nav>
|
||||
|
||||
<cre-employee-info></cre-employee-info>
|
||||
<cre-employee-menu></cre-employee-menu>
|
||||
<img
|
||||
class="flex-grow-0"
|
||||
src="assets/logo.png"
|
||||
|
|
|
@ -14,11 +14,9 @@ import {ErrorService} from '../../service/error.service'
|
|||
export class HeaderComponent extends SubscribingComponent {
|
||||
links: HeaderLink[] = [
|
||||
{route: '/color', title: 'Couleurs', requiredPermission: EmployeePermission.VIEW_RECIPES},
|
||||
{route: '/catalog', title: 'Catalogue', enabled: true, requiredPermission: EmployeePermission.VIEW_CATALOG},
|
||||
{route: '/employee', title: 'Utilisateurs', requiredPermission: EmployeePermission.VIEW_USERS},
|
||||
{route: '/group', title: 'Groupes', requiredPermission: EmployeePermission.VIEW_USERS},
|
||||
{route: '/account/login', title: 'Connexion', enabled: true},
|
||||
{route: '/account/logout', title: 'Déconnexion', enabled: false},
|
||||
{route: '/catalog', title: 'Catalogue', requiredPermission: EmployeePermission.VIEW_CATALOG},
|
||||
{route: '/misc', title: 'Autres', enabled: true},
|
||||
{route: '/admin', title: 'Administration', requiredPermission: EmployeePermission.VIEW_USERS},
|
||||
]
|
||||
_activeLink = this.links[0].route
|
||||
|
||||
|
@ -49,10 +47,10 @@ export class HeaderComponent extends SubscribingComponent {
|
|||
)
|
||||
|
||||
// Auth status
|
||||
this.updateEnabledLinks(this.appState.isAuthenticated, this.appState.authenticatedEmployee)
|
||||
this.updateEnabledLinks()
|
||||
this.subscribe(
|
||||
this.appState.authenticatedUser$,
|
||||
authentication => this.updateEnabledLinks(authentication.authenticated, authentication.authenticatedUser)
|
||||
() => this.updateEnabledLinks()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -73,20 +71,17 @@ export class HeaderComponent extends SubscribingComponent {
|
|||
return this._activeLink
|
||||
}
|
||||
|
||||
private updateEnabledLinks(authenticated: boolean, employee: Employee) {
|
||||
this.link('/account/login').enabled = !authenticated
|
||||
this.link('/account/logout').enabled = authenticated
|
||||
|
||||
private updateEnabledLinks() {
|
||||
this.links.forEach(l => {
|
||||
if (l.requiredPermission) {
|
||||
l.enabled = employee && employee.permissions.indexOf(l.requiredPermission) >= 0
|
||||
l.enabled = this.accountService.hasPermission(l.requiredPermission)
|
||||
}
|
||||
|
||||
if (l.route === '/misc') {
|
||||
l.enabled = this.accountService.hasPermission(EmployeePermission.GENERATE_TOUCH_UP_KIT)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private link(route: string) {
|
||||
return this.links.filter(l => l.route === route)[0]
|
||||
}
|
||||
}
|
||||
|
||||
class HeaderLink {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
nav
|
||||
position: relative
|
||||
z-index: 99
|
||||
z-index: 90
|
||||
padding-bottom: 1px
|
||||
|
||||
a
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import {Injectable, OnDestroy, OnInit} from '@angular/core'
|
||||
import {GlobalAlertHandlerComponent} from '../global-alert-handler/global-alert-handler.component'
|
||||
import {NavLink} from '../nav/nav.component'
|
||||
|
||||
@Injectable()
|
||||
export abstract class SubMenuComponent implements OnInit, OnDestroy {
|
||||
abstract links: NavLink[]
|
||||
|
||||
ngOnInit(): void {
|
||||
GlobalAlertHandlerComponent.extraTopMarginMultiplier = 1
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
GlobalAlertHandlerComponent.extraTopMarginMultiplier = 0
|
||||
}
|
||||
}
|
|
@ -25,8 +25,6 @@ export enum EmployeePermission {
|
|||
VIEW_USERS = 'VIEW_USERS',
|
||||
VIEW_CATALOG = 'VIEW_CATALOG',
|
||||
|
||||
PRINT_MIXES = 'PRINT_MIXES',
|
||||
|
||||
EDIT_RECIPES_PUBLIC_DATA = 'EDIT_RECIPES_PUBLIC_DATA',
|
||||
EDIT_RECIPES = 'EDIT_RECIPES',
|
||||
EDIT_MATERIALS = 'EDIT_MATERIALS',
|
||||
|
@ -42,8 +40,10 @@ export enum EmployeePermission {
|
|||
REMOVE_USERS = 'REMOVE_USERS',
|
||||
REMOVE_CATALOG = 'REMOVE_CATALOG',
|
||||
|
||||
PRINT_MIXES = 'PRINT_MIXES',
|
||||
ADD_TO_INVENTORY = 'ADD_TO_INVENTORY',
|
||||
DEDUCT_FROM_INVENTORY = 'DEDUCT_FROM_INVENTORY',
|
||||
GENERATE_TOUCH_UP_KIT = 'GENERATE_TOUCH_UP_KIT',
|
||||
|
||||
ADMIN = 'ADMIN'
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import {MaterialType} from "./materialtype.model";
|
||||
import {openPdf} from '../utils/utils'
|
||||
|
||||
export class Material {
|
||||
constructor(
|
||||
public id: number,
|
||||
public name: string,
|
||||
public inventoryQuantity: number,
|
||||
public materialType: MaterialType
|
||||
public materialType: MaterialType,
|
||||
public simdutUrl: string
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
export function openSimdut(material: Material) {
|
||||
openPdf(material.simdutUrl)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ export class Recipe {
|
|||
public remark: string,
|
||||
public company: Company,
|
||||
public mixes: Mix[],
|
||||
public groupsInformation: RecipeGroupInformation[]
|
||||
public groupsInformation: RecipeGroupInformation[],
|
||||
public imagesUrls: string[]
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@ export class ErrorService {
|
|||
}
|
||||
|
||||
const error = response.error
|
||||
if (!error || !error.type) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.activeHandler) {
|
||||
matchingModels = this.activeHandler.errorHandlers.filter(m => m.filter(error)) // Find error models whose filter matches the current error
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import {Injectable} from '@angular/core'
|
||||
import {environment} from '../../../../environments/environment'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class TouchupkitService {
|
||||
generateJobPdfDocument(job: string) {
|
||||
window.open(`${environment.apiUrl}/touchup?job=${job}`, '_blank')
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import {MatFormFieldModule} from '@angular/material/form-field'
|
|||
import {MatInputModule} from '@angular/material/input'
|
||||
import {MatIconModule} from '@angular/material/icon'
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms'
|
||||
import {EmployeeInfoComponent} from './components/employee-info/employee-info.component'
|
||||
import {EmployeeMenuComponent} from './components/employee-info/employee-menu.component'
|
||||
import {LabeledIconComponent} from './components/labeled-icon/labeled-icon.component'
|
||||
import {MatTableModule} from '@angular/material/table'
|
||||
import {CommonModule} from '@angular/common'
|
||||
|
@ -35,7 +35,7 @@ import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'
|
|||
|
||||
|
||||
@NgModule({
|
||||
declarations: [HeaderComponent, EmployeeInfoComponent, LabeledIconComponent, ConfirmBoxComponent, PermissionsListComponent, PermissionsFieldComponent, NavComponent, EntityListComponent, EntityAddComponent, EntityEditComponent, FileButtonComponent, GlobalAlertHandlerComponent, SliderFieldComponent, LoadingWheelComponent],
|
||||
declarations: [HeaderComponent, EmployeeMenuComponent, LabeledIconComponent, ConfirmBoxComponent, PermissionsListComponent, PermissionsFieldComponent, NavComponent, EntityListComponent, EntityAddComponent, EntityEditComponent, FileButtonComponent, GlobalAlertHandlerComponent, SliderFieldComponent, LoadingWheelComponent],
|
||||
exports: [
|
||||
CommonModule,
|
||||
HttpClientModule,
|
||||
|
@ -78,6 +78,7 @@ import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'
|
|||
MatInputModule,
|
||||
MatSelectModule,
|
||||
MatOptionModule,
|
||||
MatListModule,
|
||||
MatSliderModule,
|
||||
MatProgressSpinnerModule,
|
||||
ReactiveFormsModule,
|
||||
|
|
|
@ -2,3 +2,19 @@
|
|||
export function valueOr<T>(value: T, or: T): T {
|
||||
return value ? value : or
|
||||
}
|
||||
|
||||
const MEDIA_TYPE_PDF = 'application/pdf'
|
||||
const MEDIA_TYPE_JPG = 'image/jpeg'
|
||||
|
||||
export function openPdf(url: string) {
|
||||
openUrl(url, MEDIA_TYPE_PDF)
|
||||
}
|
||||
|
||||
export function openJpg(url: string) {
|
||||
openUrl(url, MEDIA_TYPE_JPG)
|
||||
}
|
||||
|
||||
function openUrl(url: string, mediaType: string) {
|
||||
const encodedUrl = `${url}&mediaType=${encodeURIComponent(mediaType)}`
|
||||
window.open(encodedUrl, '_blank')
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import {Component, ContentChildren, ViewChild, ViewContainerRef} from '@angular/core'
|
||||
import {Component, ViewChild} from '@angular/core'
|
||||
import {Validators} from '@angular/forms'
|
||||
import {
|
||||
currentPermissionsFieldComponent,
|
||||
PermissionsFieldComponent
|
||||
} from '../../../shared/components/permissions-field/permissions-field.component'
|
||||
import {currentPermissionsFieldComponent} from '../../../shared/components/permissions-field/permissions-field.component'
|
||||
import {GroupService} from '../../../groups/services/group.service'
|
||||
import {EmployeeService} from '../../services/employee.service'
|
||||
import {UserService} from '../../services/user.service'
|
||||
import {ActivatedRoute, Router} from '@angular/router'
|
||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||
|
@ -22,14 +19,14 @@ export class AddComponent extends ErrorHandlingComponent {
|
|||
|
||||
formFields: FormField[] = [{
|
||||
name: 'id',
|
||||
label: 'Numéro d\'employé',
|
||||
label: 'Numéro d\'utilisateur',
|
||||
icon: 'pound',
|
||||
type: 'number',
|
||||
required: true,
|
||||
validator: Validators.compose([Validators.pattern(new RegExp('^[0-9]+$')), Validators.min(0)]),
|
||||
errorMessages: [
|
||||
{conditionFn: errors => errors.required, message: 'Un numéro d\'employé est requis'},
|
||||
{conditionFn: errors => errors.pattern, message: 'Le numéro d\'employé doit être un nombre'}
|
||||
{conditionFn: errors => errors.required, message: 'Un numéro d\'utilisateur est requis'},
|
||||
{conditionFn: errors => errors.pattern, message: 'Le numéro d\'utilisateur doit être un nombre'}
|
||||
]
|
||||
}, {
|
||||
name: 'firstName',
|
||||
|
@ -84,7 +81,7 @@ export class AddComponent extends ErrorHandlingComponent {
|
|||
}]
|
||||
|
||||
constructor(
|
||||
private employeeService: EmployeeService,
|
||||
private employeeService: UserService,
|
||||
private groupService: GroupService,
|
||||
errorService: ErrorService,
|
||||
router: Router,
|
||||
|
@ -112,7 +109,7 @@ export class AddComponent extends ErrorHandlingComponent {
|
|||
groupId,
|
||||
permissionsField.allEnabledPermissions
|
||||
),
|
||||
'/employee/list'
|
||||
'/admin/user/list'
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import {Component, ViewChild} from '@angular/core'
|
||||
import {currentPermissionsFieldComponent} from '../../../shared/components/permissions-field/permissions-field.component'
|
||||
import {EmployeeService} from '../../services/employee.service'
|
||||
import {UserService} from '../../services/user.service'
|
||||
import {GroupService} from '../../../groups/services/group.service'
|
||||
import {ActivatedRoute, Router} from '@angular/router'
|
||||
import {Employee} from '../../../shared/model/employee'
|
||||
|
@ -21,7 +21,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
employee: Employee | null
|
||||
formFields: FormField[] = [{
|
||||
name: 'id',
|
||||
label: 'Numéro d\'employé',
|
||||
label: 'Numéro d\'utilisateur',
|
||||
icon: 'pound',
|
||||
type: 'number',
|
||||
readonly: true
|
||||
|
@ -44,7 +44,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
{conditionFn: errors => errors.required, message: 'Un nom est requis'}
|
||||
]
|
||||
}, {
|
||||
name: 'groupId',
|
||||
name: 'group',
|
||||
label: 'Groupe',
|
||||
icon: 'account-multiple',
|
||||
type: 'select',
|
||||
|
@ -60,7 +60,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
|
||||
errorHandlers: ErrorHandler[] = [{
|
||||
filter: error => error.type === 'notfound-employee-id',
|
||||
consumer: error => this.urlUtils.navigateTo('/employee/list')
|
||||
consumer: error => this.urlUtils.navigateTo('/admin/user/list')
|
||||
}, {
|
||||
filter: error => error.type === 'exists-employee-fullName',
|
||||
messageProducer: error => `Un utilisateur nommé '${error.fullName}' existe déjà`
|
||||
|
@ -68,7 +68,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
|
||||
constructor(
|
||||
private accountService: AccountService,
|
||||
private employeeService: EmployeeService,
|
||||
private employeeService: UserService,
|
||||
private groupService: GroupService,
|
||||
errorService: ErrorService,
|
||||
router: Router,
|
||||
|
@ -96,26 +96,11 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
parseInt(values.id),
|
||||
values.firstName,
|
||||
values.lastName,
|
||||
values.group,
|
||||
permissionsField.allEnabledPermissions
|
||||
),
|
||||
() => {
|
||||
// TODO de-comment when backend will be ready
|
||||
// const group = values.groupId
|
||||
// if (group >= 0) {
|
||||
// this.subscribeAndNavigate(
|
||||
// this.groupService.addEmployeeToGroup(group, this.employee),
|
||||
// '/employee/list'
|
||||
// )
|
||||
// } else {
|
||||
// if (this.employee.group) {
|
||||
// this.subscribeAndNavigate(
|
||||
// this.groupService.removeEmployeeFromGroup(this.employee),
|
||||
// '/employee/list'
|
||||
// )
|
||||
// } else {
|
||||
this.urlUtils.navigateTo('/employee/list')
|
||||
// }
|
||||
// }
|
||||
this.urlUtils.navigateTo('/admin/user/list')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -124,7 +109,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
|||
delete() {
|
||||
this.subscribeAndNavigate(
|
||||
this.employeeService.delete(this.employee.id),
|
||||
'/employee/list'
|
||||
'/admin/user/list'
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<cre-entity-list
|
||||
addLink="/employee/add"
|
||||
addLink="/admin/user/add"
|
||||
addPermission="EDIT_USERS"
|
||||
[entities$]="employees$"
|
||||
[columns]="columns"
|
|
@ -1,6 +1,6 @@
|
|||
import {Component} from '@angular/core'
|
||||
import {Observable} from 'rxjs'
|
||||
import {EmployeeService} from '../../services/employee.service'
|
||||
import {UserService} from '../../services/user.service'
|
||||
import {Employee, EmployeePermission} from '../../../shared/model/employee'
|
||||
import {takeUntil} from 'rxjs/operators'
|
||||
import {AccountService} from '../../../accounts/services/account.service'
|
||||
|
@ -24,7 +24,7 @@ import {ErrorService} from '../../../shared/service/error.service'
|
|||
export class ListComponent extends ErrorHandlingComponent {
|
||||
employees$: Observable<Employee[]>
|
||||
columns = [
|
||||
{def: 'id', title: 'Numéro d\'employé', valueFn: e => e.id},
|
||||
{def: 'id', title: 'Numéro d\'utilisateur', valueFn: e => e.id},
|
||||
{def: 'name', title: 'Nom', valueFn: e => `${e.firstName} ${e.lastName}`},
|
||||
{def: 'group', title: 'Groupe', valueFn: e => e.group ? e.group.name : 'Aucun'},
|
||||
{def: 'permissionCount', title: 'Nombre de permissions', valueFn: e => e.permissions.length},
|
||||
|
@ -32,16 +32,16 @@ export class ListComponent extends ErrorHandlingComponent {
|
|||
]
|
||||
buttons = [{
|
||||
text: 'Modifier',
|
||||
linkFn: employee => `/employee/edit/${employee.id}`,
|
||||
linkFn: employee => `/admin/user/edit/${employee.id}`,
|
||||
permission: EmployeePermission.EDIT_USERS
|
||||
}, {
|
||||
text: 'Modifier mot de passe',
|
||||
linkFn: employee => `/employee/password/edit/${employee.id}`,
|
||||
linkFn: employee => `/admin/user/password/edit/${employee.id}`,
|
||||
permission: EmployeePermission.EDIT_USERS
|
||||
}]
|
||||
|
||||
constructor(
|
||||
private employeeService: EmployeeService,
|
||||
private employeeService: UserService,
|
||||
private accountService: AccountService,
|
||||
errorService: ErrorService,
|
||||
router: Router,
|
|
@ -1,6 +1,6 @@
|
|||
import {Component} from '@angular/core'
|
||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||
import {EmployeeService} from '../../services/employee.service'
|
||||
import {UserService} from '../../services/user.service'
|
||||
import {Employee} from '../../../shared/model/employee'
|
||||
import {ActivatedRoute, Router} from '@angular/router'
|
||||
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'
|
||||
|
@ -19,11 +19,11 @@ export class PasswordEditComponent extends ErrorHandlingComponent {
|
|||
|
||||
errorHandlers: ErrorHandler[] = [{
|
||||
filter: error => error.type === 'notfound-employee-id',
|
||||
consumer: error => this.urlUtils.navigateTo('/employee/list')
|
||||
consumer: error => this.urlUtils.navigateTo('/admin/user/list')
|
||||
}]
|
||||
|
||||
constructor(
|
||||
private employeeService: EmployeeService,
|
||||
private employeeService: UserService,
|
||||
private formBuilder: FormBuilder,
|
||||
errorService: ErrorService,
|
||||
router: Router,
|
||||
|
@ -49,7 +49,7 @@ export class PasswordEditComponent extends ErrorHandlingComponent {
|
|||
if (this.form.valid) {
|
||||
this.subscribeAndNavigate(
|
||||
this.employeeService.updatePassword(this.employee.id, this.passwordControl.value),
|
||||
'/employee/list'
|
||||
'/admin/user/list'
|
||||
)
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import {Observable} from "rxjs";
|
|||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class EmployeeService {
|
||||
export class UserService {
|
||||
constructor(
|
||||
private api: ApiService
|
||||
) {
|
||||
|
@ -25,8 +25,8 @@ export class EmployeeService {
|
|||
return this.api.post<Employee>('/employee', employee)
|
||||
}
|
||||
|
||||
update(id: number, firstName: string, lastName: string, permissions: EmployeePermission[]): Observable<void> {
|
||||
const employee = {id, firstName, lastName, permissions}
|
||||
update(id: number, firstName: string, lastName: string, group: number, permissions: EmployeePermission[]): Observable<void> {
|
||||
const employee = {id, firstName, lastName, groupId: group, permissions}
|
||||
return this.api.put<void>('/employee', employee)
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import {NgModule} from '@angular/core'
|
||||
import {Routes, RouterModule} from '@angular/router'
|
||||
|
||||
import {ListComponent} from './pages/list/list.component'
|
||||
import {AddComponent} from './pages/add/add.component'
|
||||
import {EditComponent} from './pages/edit/edit.component'
|
||||
import {PasswordEditComponent} from './pages/password-edit/password-edit.component'
|
||||
|
||||
const routes: Routes = [{
|
||||
path: 'list',
|
||||
component: ListComponent
|
||||
}, {
|
||||
path: 'add', component: AddComponent
|
||||
}, {
|
||||
path: 'edit/:id',
|
||||
component: EditComponent
|
||||
}, {
|
||||
path: 'password/edit/:id', component: PasswordEditComponent
|
||||
}, {
|
||||
path: '', redirectTo: 'list'
|
||||
}]
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class UserRoutingModule {
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
|
||||
import {EmployeesRoutingModule} from './employees-routing.module';
|
||||
import {UserRoutingModule} from './user-routing.module';
|
||||
import {ListComponent} from './pages/list/list.component';
|
||||
import {SharedModule} from "../shared/shared.module";
|
||||
import { AddComponent } from './pages/add/add.component';
|
||||
|
@ -12,9 +12,9 @@ import { PasswordEditComponent } from './pages/password-edit/password-edit.compo
|
|||
@NgModule({
|
||||
declarations: [ListComponent, AddComponent, EditComponent, PasswordEditComponent],
|
||||
imports: [
|
||||
EmployeesRoutingModule,
|
||||
UserRoutingModule,
|
||||
SharedModule,
|
||||
MatSelectModule
|
||||
]
|
||||
})
|
||||
export class EmployeesModule { }
|
||||
export class UserModule { }
|
|
@ -0,0 +1,2 @@
|
|||
<cre-nav [links]="links"></cre-nav>
|
||||
<router-outlet></router-outlet>
|
|
@ -0,0 +1,16 @@
|
|||
import {Component} from '@angular/core'
|
||||
import {SubMenuComponent} from '../../modules/shared/components/sub-menu/sub-menu.component'
|
||||
import {NavLink} from '../../modules/shared/components/nav/nav.component'
|
||||
import {EmployeePermission} from '../../modules/shared/model/employee'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-administration',
|
||||
templateUrl: './administration.component.html',
|
||||
styleUrls: ['./administration.component.sass']
|
||||
})
|
||||
export class AdministrationComponent extends SubMenuComponent {
|
||||
links: NavLink[] = [
|
||||
{route: '/admin/user', title: 'Utilisateurs', permission: EmployeePermission.VIEW_USERS},
|
||||
{route: '/admin/group', title: 'Groupes', permission: EmployeePermission.VIEW_USERS},
|
||||
]
|
||||
}
|
|
@ -1,25 +1,17 @@
|
|||
import {Component, OnDestroy, OnInit} from '@angular/core'
|
||||
import {Component} from '@angular/core'
|
||||
import {NavLink} from '../../modules/shared/components/nav/nav.component'
|
||||
import {EmployeePermission} from '../../modules/shared/model/employee'
|
||||
import {GlobalAlertHandlerComponent} from '../../modules/shared/components/global-alert-handler/global-alert-handler.component'
|
||||
import {SubMenuComponent} from '../../modules/shared/components/sub-menu/sub-menu.component'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-inventory-page',
|
||||
templateUrl: './catalog.component.html',
|
||||
styleUrls: ['./catalog.component.sass']
|
||||
})
|
||||
export class CatalogComponent implements OnInit, OnDestroy {
|
||||
export class CatalogComponent extends SubMenuComponent {
|
||||
links: NavLink[] = [
|
||||
{route: '/catalog/materialtype', title: 'Types de produit', permission: EmployeePermission.VIEW_CATALOG},
|
||||
{route: '/catalog/material', title: 'Inventaire', permission: EmployeePermission.VIEW_CATALOG},
|
||||
{route: '/catalog/company', title: 'Bannières', permission: EmployeePermission.VIEW_CATALOG}
|
||||
]
|
||||
|
||||
ngOnInit(): void {
|
||||
GlobalAlertHandlerComponent.extraTopMarginMultiplier = 1
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
GlobalAlertHandlerComponent.extraTopMarginMultiplier = 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<cre-nav [links]="links"></cre-nav>
|
||||
<router-outlet></router-outlet>
|
|
@ -0,0 +1,15 @@
|
|||
import {Component} from '@angular/core'
|
||||
import {SubMenuComponent} from '../../modules/shared/components/sub-menu/sub-menu.component'
|
||||
import {NavLink} from '../../modules/shared/components/nav/nav.component'
|
||||
import {EmployeePermission} from '../../modules/shared/model/employee'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-others',
|
||||
templateUrl: './misc.component.html',
|
||||
styleUrls: ['./misc.component.sass']
|
||||
})
|
||||
export class MiscComponent extends SubMenuComponent{
|
||||
links: NavLink[] = [
|
||||
{route: '/misc/touchupkit', title: 'Kits de retouche', permission: EmployeePermission.GENERATE_TOUCH_UP_KIT}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue