#14 Update recipe editor
This commit is contained in:
parent
c35635c596
commit
521db72f5e
|
@ -4,6 +4,8 @@
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content [class.no-action]="!editionMode">
|
<mat-card-content [class.no-action]="!editionMode">
|
||||||
<div class="d-flex flex-row justify-content-around flex-wrap">
|
<div class="d-flex flex-row justify-content-around flex-wrap">
|
||||||
|
<p *ngIf="imagesUrls.length <= 0" class="light-text text-center">Aucune image n'est associée à cette couleur</p>
|
||||||
|
|
||||||
<div *ngFor="let imageUrl of imagesUrls" 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">
|
<div class="image-wrapper">
|
||||||
<img [src]="imageUrl" width="300px"/>
|
<img [src]="imageUrl" width="300px"/>
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
<mat-card-title>Mélanges</mat-card-title>
|
<mat-card-title>Mélanges</mat-card-title>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content [class.no-action]="!editionMode">
|
<mat-card-content [class.no-action]="!editionMode">
|
||||||
|
<p *ngIf="recipe.mixes.length <= 0" class="light-text text-center">Il n'y a aucun mélange dans cette couleur</p>
|
||||||
|
|
||||||
<ng-container *ngFor="let mix of recipe.mixes; let i = index">
|
<ng-container *ngFor="let mix of recipe.mixes; let i = index">
|
||||||
<cre-mix-table
|
<cre-mix-table
|
||||||
[class.no-top-margin]="i == 0"
|
[class.no-top-margin]="i == 0"
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<div *ngIf="recipe">
|
||||||
|
<cre-action-bar>
|
||||||
|
<cre-action-group>
|
||||||
|
<cre-primary-button routerLink="/color/list">Retour</cre-primary-button>
|
||||||
|
<cre-unit-selector (unitChange)="changeUnits($event)"></cre-unit-selector>
|
||||||
|
</cre-action-group>
|
||||||
|
<cre-action-group>
|
||||||
|
<cre-warn-button (click)="deleteConfirmBox.show()">Supprimer</cre-warn-button>
|
||||||
|
<cre-accent-button (click)="submit()">Enregistrer</cre-accent-button>
|
||||||
|
</cre-action-group>
|
||||||
|
</cre-action-bar>
|
||||||
|
|
||||||
|
<div class="recipe-wrapper d-flex flex-row justify-content-around align-items-start flex-wrap">
|
||||||
|
<section>
|
||||||
|
<recipe-form [recipe]="recipe"></recipe-form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<cre-mixes-card [recipe]="recipe" [units$]="units$" [editionMode]="true"></cre-mixes-card>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<cre-step-table [recipe]="recipe" [groups$]="groups$" [selectedGroupId]="loggedInUserGroupId"></cre-step-table>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<cre-images-editor [recipe]="recipe" [editionMode]="true"></cre-images-editor>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<cre-confirm-box
|
||||||
|
#deleteConfirmBox
|
||||||
|
message="Voulez-vous vraiment supprimer la couleur {{recipe?.name}}?"
|
||||||
|
(confirm)="delete()">
|
||||||
|
</cre-confirm-box>
|
|
@ -1,12 +1,13 @@
|
||||||
<div class="mt-5">
|
<div *ngIf="!loading && !hasCompanies" class="mt-5">
|
||||||
<cre-warning-alert *ngIf="!loading && !hasCompanies">
|
<cre-warning-alert>
|
||||||
<p>Il n'y a actuellement aucune bannière enregistrée dans le système.</p>
|
<p>Il n'y a actuellement aucune bannière enregistrée dans le système.</p>
|
||||||
<p *ngIf="hasCompanyEditPermission">Vous pouvez en créer une <b><a routerLink="/catalog/company/add">ici</a></b>.</p>
|
<p *ngIf="hasCompanyEditPermission">Vous pouvez en créer une <b><a routerLink="/catalog/company/add">ici</a></b>.</p>
|
||||||
</cre-warning-alert>
|
</cre-warning-alert>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<cre-form *ngIf="hasCompanies" #form [formControls]="controls" class="mx-auto">
|
<cre-form *ngIf="hasCompanies" #form [formControls]="controls" class="mx-auto">
|
||||||
<cre-form-title>Ajouter une recette</cre-form-title>
|
<cre-form-title *ngIf="!recipe">Ajouter une couleur</cre-form-title>
|
||||||
|
<cre-form-title *ngIf="recipe">Modifier la couleur {{recipe.name}}</cre-form-title>
|
||||||
<cre-form-content>
|
<cre-form-content>
|
||||||
<cre-input [control]="controls.name" label="Name" icon="form-textbox"></cre-input>
|
<cre-input [control]="controls.name" label="Name" icon="form-textbox"></cre-input>
|
||||||
<cre-input [control]="controls.description" label="Description" icon="text"></cre-input>
|
<cre-input [control]="controls.description" label="Description" icon="text"></cre-input>
|
||||||
|
@ -17,7 +18,7 @@
|
||||||
<cre-input [control]="controls.remark" label="Remarque" icon="text"></cre-input>
|
<cre-input [control]="controls.remark" label="Remarque" icon="text"></cre-input>
|
||||||
<cre-combo-box [control]="controls.company" label="Bannière" [entries]="companyEntries$"></cre-combo-box>
|
<cre-combo-box [control]="controls.company" label="Bannière" [entries]="companyEntries$"></cre-combo-box>
|
||||||
</cre-form-content>
|
</cre-form-content>
|
||||||
<cre-form-actions>
|
<cre-form-actions *ngIf="!recipe">
|
||||||
<cre-primary-button routerLink="/color/list">Retour</cre-primary-button>
|
<cre-primary-button routerLink="/color/list">Retour</cre-primary-button>
|
||||||
<cre-accent-button [disabled]="form.invalid" (click)="submit()">Enregistrer</cre-accent-button>
|
<cre-accent-button [disabled]="form.invalid" (click)="submit()">Enregistrer</cre-accent-button>
|
||||||
</cre-form-actions>
|
</cre-form-actions>
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
<div *ngIf="recipe">
|
|
||||||
<div class="action-bar backward">
|
|
||||||
<div class="d-flex flex-column">
|
|
||||||
<div class="mt-1 pb-2">
|
|
||||||
<button mat-raised-button color="primary" routerLink="/color/list">Retour</button>
|
|
||||||
<button
|
|
||||||
mat-raised-button
|
|
||||||
color="accent"
|
|
||||||
[disabled]="editComponent.form && editComponent.form.invalid"
|
|
||||||
(click)="submit(editComponent, stepTable)">
|
|
||||||
Enregistrer
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
mat-raised-button
|
|
||||||
color="warn"
|
|
||||||
(click)="confirmBoxComponent.show()">
|
|
||||||
Supprimer
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label>Unités</mat-label>
|
|
||||||
<mat-select [value]="unitConstants.UNIT_MILLILITER" (selectionChange)="changeUnits($event.value)">
|
|
||||||
<mat-option [value]="unitConstants.UNIT_MILLILITER">Millilitres</mat-option>
|
|
||||||
<mat-option [value]="unitConstants.UNIT_LITER">Litres</mat-option>
|
|
||||||
<mat-option [value]="unitConstants.UNIT_GALLON">Gallons</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="recipe-wrapper d-flex flex-row justify-content-around align-items-start flex-wrap">
|
|
||||||
<div>
|
|
||||||
<cre-entity-edit
|
|
||||||
#editComponent
|
|
||||||
title="Modifier la couleur {{recipe.name}}"
|
|
||||||
deleteConfirmMessage="Voulez-vous vraiment supprimer la couleur {{recipe.name}}?"
|
|
||||||
[entity]="recipe"
|
|
||||||
[formFields]="formFields"
|
|
||||||
[disableButtons]="true"
|
|
||||||
[noTopMargin]="true">
|
|
||||||
</cre-entity-edit>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="recipe-mixes-wrapper">
|
|
||||||
<cre-mixes-card [recipe]="recipe" [units$]="units$" [editionMode]="true"></cre-mixes-card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<cre-step-table
|
|
||||||
#stepTable
|
|
||||||
[recipe]="recipe"
|
|
||||||
[groups$]="groups$"
|
|
||||||
[selectedGroupId]="loggedInUserGroupId">
|
|
||||||
</cre-step-table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<cre-images-editor #imagesEditor [recipe]="recipe" [editionMode]="true"></cre-images-editor>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<cre-confirm-box
|
|
||||||
#confirmBoxComponent
|
|
||||||
message="Voulez-vous vraiment supprimer la couleur {{recipe?.name}}?"
|
|
||||||
(confirm)="delete()">
|
|
||||||
</cre-confirm-box>
|
|
|
@ -1,2 +0,0 @@
|
||||||
.recipe-wrapper > div
|
|
||||||
margin: 0 3rem 3rem
|
|
|
@ -1,186 +0,0 @@
|
||||||
import {Component, ViewChild} from '@angular/core'
|
|
||||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
|
||||||
import {Recipe, recipeMixCount, RecipeStep, recipeStepCount} from '../../../shared/model/recipe.model'
|
|
||||||
import {RecipeService} from '../../services/recipe.service'
|
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
|
||||||
import {Validators} from '@angular/forms'
|
|
||||||
import {Subject} from 'rxjs'
|
|
||||||
import {UNIT_GALLON, UNIT_LITER, UNIT_MILLILITER} from '../../../shared/units'
|
|
||||||
import {AccountService} from '../../../accounts/services/account.service'
|
|
||||||
import {EntityEditComponent} from '../../../shared/components/entity-edit/entity-edit.component'
|
|
||||||
import {ImagesEditorComponent} from '../../components/images-editor/images-editor.component'
|
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
|
||||||
import {AlertService} from '../../../shared/service/alert.service'
|
|
||||||
import {GroupService} from '../../../groups/services/group.service'
|
|
||||||
import {AppState} from '../../../shared/app-state'
|
|
||||||
import {StepTableComponent} from '../../components/step-table/step-table.component'
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'cre-edit',
|
|
||||||
templateUrl: './edit.component.html',
|
|
||||||
styleUrls: ['./edit.component.sass']
|
|
||||||
})
|
|
||||||
export class EditComponent extends ErrorHandlingComponent {
|
|
||||||
readonly unitConstants = {UNIT_MILLILITER, UNIT_LITER, UNIT_GALLON}
|
|
||||||
|
|
||||||
@ViewChild('imagesEditor') imagesEditor: ImagesEditorComponent
|
|
||||||
|
|
||||||
recipe: Recipe | null
|
|
||||||
groups$ = this.groupService.all
|
|
||||||
formFields = [
|
|
||||||
{
|
|
||||||
name: 'name',
|
|
||||||
label: 'Nom',
|
|
||||||
icon: 'form-textbox',
|
|
||||||
type: 'text',
|
|
||||||
required: true,
|
|
||||||
errorMessages: [
|
|
||||||
{conditionFn: errors => errors.required, message: 'Un nom est requis'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'description',
|
|
||||||
label: 'Description',
|
|
||||||
icon: 'text',
|
|
||||||
type: 'text',
|
|
||||||
required: true,
|
|
||||||
errorMessages: [
|
|
||||||
{conditionFn: errors => errors.required, message: 'Une description est requise'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'color',
|
|
||||||
label: 'Couleur',
|
|
||||||
icon: 'palette',
|
|
||||||
type: 'color',
|
|
||||||
required: true,
|
|
||||||
errorMessages: [
|
|
||||||
{conditionFn: errors => errors.required, message: 'Une couleur est requise'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'gloss',
|
|
||||||
label: 'Lustre',
|
|
||||||
type: 'slider',
|
|
||||||
min: 0,
|
|
||||||
max: 100,
|
|
||||||
validator: Validators.compose([Validators.required, Validators.min(0), Validators.max(100)]),
|
|
||||||
errorMessages: [
|
|
||||||
{conditionFn: errors => errors.required, message: 'Le lustre de la couleur est requis'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'sample',
|
|
||||||
label: 'Échantillon',
|
|
||||||
icon: 'pound',
|
|
||||||
type: 'number',
|
|
||||||
validator: Validators.min(0),
|
|
||||||
errorMessages: [
|
|
||||||
{conditionFn: errors => errors.required, message: 'Un numéro d\'échantillon est requis'},
|
|
||||||
{conditionFn: errors => errors.min, message: 'Le numéro d\'échantillon doit être supérieur ou égal à 0'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'approbationDate',
|
|
||||||
label: 'Date d\'approbation',
|
|
||||||
icon: 'calendar',
|
|
||||||
type: 'date'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'remark',
|
|
||||||
label: 'Remarque',
|
|
||||||
icon: 'text',
|
|
||||||
type: 'text'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'company',
|
|
||||||
label: 'Bannière',
|
|
||||||
icon: 'domain',
|
|
||||||
type: 'text',
|
|
||||||
readonly: true,
|
|
||||||
valueFn: recipe => recipe.company.name,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
units$ = new Subject<string>()
|
|
||||||
submittedValues: any | null
|
|
||||||
|
|
||||||
errorHandlers: ErrorHandler[] = [{
|
|
||||||
filter: error => error.type === 'notfound-recipe-id',
|
|
||||||
consumer: error => this.urlUtils.navigateTo('/color/list')
|
|
||||||
}]
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private recipeService: RecipeService,
|
|
||||||
private groupService: GroupService,
|
|
||||||
private accountService: AccountService,
|
|
||||||
private alertService: AlertService,
|
|
||||||
private appState: AppState,
|
|
||||||
errorService: ErrorService,
|
|
||||||
router: Router,
|
|
||||||
activatedRoute: ActivatedRoute
|
|
||||||
) {
|
|
||||||
super(errorService, activatedRoute, router)
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
super.ngOnInit()
|
|
||||||
|
|
||||||
this.subscribeEntityById(
|
|
||||||
this.recipeService,
|
|
||||||
parseInt(this.activatedRoute.snapshot.paramMap.get('id')),
|
|
||||||
recipe => {
|
|
||||||
this.recipe = recipe
|
|
||||||
this.appState.title = `${recipe.name} (Modifications)`
|
|
||||||
|
|
||||||
if (recipeMixCount(this.recipe) == 0) {
|
|
||||||
this.alertService.pushWarning('Il n\'y a aucun mélange dans cette recette')
|
|
||||||
}
|
|
||||||
if (recipeStepCount(this.recipe) == 0) {
|
|
||||||
this.alertService.pushWarning('Il n\'y a aucune étape dans cette recette')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
changeUnits(unit: string) {
|
|
||||||
this.units$.next(unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
submit(editComponent: EntityEditComponent, stepTable: StepTableComponent) {
|
|
||||||
const values = editComponent.values
|
|
||||||
this.submittedValues = values
|
|
||||||
|
|
||||||
const steps = stepTable.mappedUpdatedSteps
|
|
||||||
if (!this.stepsPositionsAreValid(steps)) {
|
|
||||||
this.alertService.pushError('Les étapes ne peuvent pas avoir une position inférieure à 1')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.subscribeAndNavigate(
|
|
||||||
this.recipeService.update(this.recipe.id, values.name, values.description, values.color, values.gloss, values.sample, values.approbationDate, values.remark, steps),
|
|
||||||
'/color/list'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
delete() {
|
|
||||||
this.subscribeAndNavigate(
|
|
||||||
this.recipeService.delete(this.recipe.id),
|
|
||||||
'/color/list'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
get loggedInUserGroupId(): number {
|
|
||||||
return this.appState.authenticatedUser.group?.id
|
|
||||||
}
|
|
||||||
|
|
||||||
private stepsPositionsAreValid(steps: Map<number, RecipeStep[]>): boolean {
|
|
||||||
let valid = true
|
|
||||||
steps.forEach((steps, _) => {
|
|
||||||
if (steps.find(s => s.position === 0)) {
|
|
||||||
valid = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return valid
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +1,10 @@
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {RouterModule, Routes} from '@angular/router';
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
import {ListComponent} from "./pages/list/list.component";
|
import {ListComponent} from './pages/list/list.component';
|
||||||
import {EditComponent} from "./pages/edit/edit.component";
|
import {ExploreComponent} from './pages/explore/explore.component';
|
||||||
import {ExploreComponent} from "./pages/explore/explore.component";
|
import {MixEditComponent} from './pages/mix/mix-edit/mix-edit.component';
|
||||||
import {MixEditComponent} from "./pages/mix/mix-edit/mix-edit.component";
|
import {MixAddComponent} from './pages/mix/mix-add/mix-add.component';
|
||||||
import {MixAddComponent} from "./pages/mix/mix-add/mix-add.component";
|
import {RecipeAdd, RecipeEdit} from './recipes';
|
||||||
import {RecipeAdd} from './recipes';
|
|
||||||
|
|
||||||
const routes: Routes = [{
|
const routes: Routes = [{
|
||||||
path: 'list',
|
path: 'list',
|
||||||
|
@ -15,7 +14,7 @@ const routes: Routes = [{
|
||||||
component: RecipeAdd
|
component: RecipeAdd
|
||||||
}, {
|
}, {
|
||||||
path: 'edit/:id',
|
path: 'edit/:id',
|
||||||
component: EditComponent
|
component: RecipeEdit
|
||||||
}, {
|
}, {
|
||||||
path: 'add/mix/:recipeId',
|
path: 'add/mix/:recipeId',
|
||||||
component: MixAddComponent
|
component: MixAddComponent
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {NgModule} from '@angular/core'
|
||||||
import {RecipesRoutingModule} from './recipes-routing.module'
|
import {RecipesRoutingModule} from './recipes-routing.module'
|
||||||
import {SharedModule} from '../shared/shared.module'
|
import {SharedModule} from '../shared/shared.module'
|
||||||
import {ListComponent} from './pages/list/list.component'
|
import {ListComponent} from './pages/list/list.component'
|
||||||
import {EditComponent} from './pages/edit/edit.component'
|
|
||||||
import {MatExpansionModule} from '@angular/material/expansion'
|
import {MatExpansionModule} from '@angular/material/expansion'
|
||||||
import {FormsModule} from '@angular/forms'
|
import {FormsModule} from '@angular/forms'
|
||||||
import {ExploreComponent} from './pages/explore/explore.component'
|
import {ExploreComponent} from './pages/explore/explore.component'
|
||||||
|
@ -20,13 +19,13 @@ import {MixesCardComponent} from './components/mixes-card/mixes-card.component'
|
||||||
import {MatSortModule} from '@angular/material/sort'
|
import {MatSortModule} from '@angular/material/sort'
|
||||||
import {CreInputsModule} from '../shared/components/inputs/inputs.module';
|
import {CreInputsModule} from '../shared/components/inputs/inputs.module';
|
||||||
import {CreButtonsModule} from '../shared/components/buttons/buttons.module';
|
import {CreButtonsModule} from '../shared/components/buttons/buttons.module';
|
||||||
import {RecipeAdd, RecipeForm} from './recipes';
|
import {RecipeAdd, RecipeEdit, RecipeForm} from './recipes';
|
||||||
|
import {CreActionBarModule} from '../shared/components/action-bar/action-bar.module';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
ListComponent,
|
ListComponent,
|
||||||
EditComponent,
|
|
||||||
ExploreComponent,
|
ExploreComponent,
|
||||||
RecipeInfoComponent,
|
RecipeInfoComponent,
|
||||||
MixTableComponent,
|
MixTableComponent,
|
||||||
|
@ -39,7 +38,8 @@ import {RecipeAdd, RecipeForm} from './recipes';
|
||||||
ImagesEditorComponent,
|
ImagesEditorComponent,
|
||||||
MixesCardComponent,
|
MixesCardComponent,
|
||||||
RecipeForm,
|
RecipeForm,
|
||||||
RecipeAdd
|
RecipeAdd,
|
||||||
|
RecipeEdit
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
UnitSelectorComponent
|
UnitSelectorComponent
|
||||||
|
@ -51,7 +51,8 @@ import {RecipeAdd, RecipeForm} from './recipes';
|
||||||
FormsModule,
|
FormsModule,
|
||||||
MatSortModule,
|
MatSortModule,
|
||||||
CreInputsModule,
|
CreInputsModule,
|
||||||
CreButtonsModule
|
CreButtonsModule,
|
||||||
|
CreActionBarModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class RecipesModule {
|
export class RecipesModule {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
.recipe-wrapper > section
|
||||||
|
margin: 0 3rem 3rem
|
||||||
|
|
||||||
|
cre-form
|
||||||
|
margin-top: 0 !important
|
||||||
|
|
|
@ -1,56 +1,27 @@
|
||||||
import {ErrorHandlingComponent, SubscribingComponent} from '../shared/components/subscribing.component';
|
import {ErrorHandlingComponent, SubscribingComponent} from '../shared/components/subscribing.component';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable, Subject} from 'rxjs';
|
||||||
import {ComboBoxEntry} from '../shared/components/inputs/inputs';
|
import {ComboBoxEntry} from '../shared/components/inputs/inputs';
|
||||||
import {map, tap} from 'rxjs/operators';
|
import {map, tap} from 'rxjs/operators';
|
||||||
import {RecipeService} from './services/recipe.service';
|
import {RecipeService} from './services/recipe.service';
|
||||||
import {CompanyService} from '../company/service/company.service';
|
import {CompanyService} from '../company/service/company.service';
|
||||||
import {AppState} from '../shared/app-state';
|
import {AppState} from '../shared/app-state';
|
||||||
import {ErrorService} from '../shared/service/error.service';
|
import {ErrorHandler, ErrorService} from '../shared/service/error.service';
|
||||||
import {ActivatedRoute, Router} from '@angular/router';
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
import {FormControl, Validators} from '@angular/forms';
|
import {FormControl, Validators} from '@angular/forms';
|
||||||
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
import {Component, EventEmitter, Input, Output, ViewChild, ViewEncapsulation} from '@angular/core';
|
||||||
import {Recipe} from '../shared/model/recipe.model';
|
import {Recipe, recipeMixCount, RecipeStep, recipeStepCount} from '../shared/model/recipe.model';
|
||||||
import {AccountService} from '../accounts/services/account.service';
|
import {AccountService} from '../accounts/services/account.service';
|
||||||
import {Permission} from '../shared/model/user';
|
import {Permission} from '../shared/model/user';
|
||||||
|
import {AlertService} from '../shared/service/alert.service';
|
||||||
@Component({
|
import {GroupService} from '../groups/services/group.service';
|
||||||
selector: 'cre-recipe-add',
|
import {StepTableComponent} from './components/step-table/step-table.component';
|
||||||
templateUrl: 'add.html'
|
import {anyMap} from '../shared/utils/map.utils';
|
||||||
})
|
|
||||||
export class RecipeAdd extends ErrorHandlingComponent {
|
|
||||||
controls: any
|
|
||||||
companyEntries$: Observable<ComboBoxEntry[]> = this.companyService.all.pipe(
|
|
||||||
map(companies => companies.map(c => new ComboBoxEntry(c.id, c.name))),
|
|
||||||
)
|
|
||||||
|
|
||||||
errorHandlers = [{
|
|
||||||
filter: error => error.type === `exists-recipe-company-name`,
|
|
||||||
messageProducer: error => `Une couleur avec le nom ${error.name} existe déjà pour la bannière ${error.company}`
|
|
||||||
}]
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private recipeService: RecipeService,
|
|
||||||
private companyService: CompanyService,
|
|
||||||
private appState: AppState,
|
|
||||||
errorService: ErrorService,
|
|
||||||
router: Router,
|
|
||||||
activatedRoute: ActivatedRoute
|
|
||||||
) {
|
|
||||||
super(errorService, activatedRoute, router)
|
|
||||||
this.appState.title = 'Nouvelle couleur'
|
|
||||||
}
|
|
||||||
|
|
||||||
submit(recipe: Recipe) {
|
|
||||||
this.subscribe(
|
|
||||||
this.recipeService.save(recipe),
|
|
||||||
recipe => this.urlUtils.navigateTo(`/color/edit/${recipe.id}`)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'recipe-form',
|
selector: 'recipe-form',
|
||||||
templateUrl: 'form.html'
|
templateUrl: 'form.html',
|
||||||
|
styleUrls: ['recipes.sass'],
|
||||||
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class RecipeForm extends SubscribingComponent {
|
export class RecipeForm extends SubscribingComponent {
|
||||||
@Input() recipe: Recipe | null
|
@Input() recipe: Recipe | null
|
||||||
|
@ -77,14 +48,14 @@ export class RecipeForm extends SubscribingComponent {
|
||||||
this.fetchCompanies()
|
this.fetchCompanies()
|
||||||
|
|
||||||
this.controls = {
|
this.controls = {
|
||||||
name: new FormControl(null, Validators.required),
|
name: new FormControl(this.recipe?.name, Validators.required),
|
||||||
description: new FormControl(null, Validators.required),
|
description: new FormControl(this.recipe?.description, Validators.required),
|
||||||
color: new FormControl('#ffffff', Validators.required),
|
color: new FormControl(this.recipe?.color ?? '#ffffff', Validators.required),
|
||||||
gloss: new FormControl(0, Validators.compose([Validators.required, Validators.min(0), Validators.max(100)])),
|
gloss: new FormControl(this.recipe?.gloss ?? 0, Validators.compose([Validators.required, Validators.min(0), Validators.max(100)])),
|
||||||
sample: new FormControl(null, Validators.compose([Validators.required, Validators.min(0)])),
|
sample: new FormControl(this.recipe?.sample, Validators.compose([Validators.required, Validators.min(0)])),
|
||||||
approbationDate: new FormControl(null),
|
approbationDate: new FormControl(this.recipe?.approbationDate),
|
||||||
remark: new FormControl(null),
|
remark: new FormControl(this.recipe?.remark),
|
||||||
company: new FormControl(null, Validators.required)
|
company: new FormControl({value: this.recipe?.company.id, disabled: !!this.recipe}, Validators.required)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,8 +67,12 @@ export class RecipeForm extends SubscribingComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
this.submitForm.emit({
|
this.submitForm.emit(this.updatedRecipe)
|
||||||
id: this.recipe?.id,
|
}
|
||||||
|
|
||||||
|
get updatedRecipe(): Recipe {
|
||||||
|
return {
|
||||||
|
...this.recipe,
|
||||||
name: this.controls.name.value,
|
name: this.controls.name.value,
|
||||||
description: this.controls.description.value,
|
description: this.controls.description.value,
|
||||||
color: this.controls.color.value,
|
color: this.controls.color.value,
|
||||||
|
@ -106,14 +81,128 @@ export class RecipeForm extends SubscribingComponent {
|
||||||
approbationDate: this.controls.approbationDate.value,
|
approbationDate: this.controls.approbationDate.value,
|
||||||
remark: this.controls.remark.value,
|
remark: this.controls.remark.value,
|
||||||
company: this.controls.company.value,
|
company: this.controls.company.value,
|
||||||
mixes: this.recipe?.mixes,
|
}
|
||||||
approbationExpired: this.recipe?.approbationExpired,
|
|
||||||
groupsInformation: this.recipe?.groupsInformation,
|
|
||||||
imagesUrls: this.recipe?.imagesUrls
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasCompanyEditPermission(): boolean {
|
get hasCompanyEditPermission(): boolean {
|
||||||
return this.accountService.hasPermission(Permission.EDIT_COMPANIES)
|
return this.accountService.hasPermission(Permission.EDIT_COMPANIES)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cre-recipe-add',
|
||||||
|
templateUrl: 'add.html'
|
||||||
|
})
|
||||||
|
export class RecipeAdd extends ErrorHandlingComponent {
|
||||||
|
errorHandlers = [{
|
||||||
|
filter: error => error.type === `exists-recipe-company-name`,
|
||||||
|
messageProducer: error => `Une couleur avec le nom ${error.name} existe déjà pour la bannière ${error.company}`
|
||||||
|
}]
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private recipeService: RecipeService,
|
||||||
|
private companyService: CompanyService,
|
||||||
|
private appState: AppState,
|
||||||
|
errorService: ErrorService,
|
||||||
|
router: Router,
|
||||||
|
activatedRoute: ActivatedRoute
|
||||||
|
) {
|
||||||
|
super(errorService, activatedRoute, router)
|
||||||
|
this.appState.title = 'Nouvelle couleur'
|
||||||
|
}
|
||||||
|
|
||||||
|
submit(recipe: Recipe) {
|
||||||
|
this.subscribe(
|
||||||
|
this.recipeService.save(recipe),
|
||||||
|
recipe => this.urlUtils.navigateTo(`/color/edit/${recipe.id}`)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cre-recipe-edit',
|
||||||
|
templateUrl: 'edit.html',
|
||||||
|
styleUrls: ['recipes.sass']
|
||||||
|
})
|
||||||
|
export class RecipeEdit extends ErrorHandlingComponent {
|
||||||
|
@ViewChild(StepTableComponent) stepTable: StepTableComponent
|
||||||
|
@ViewChild(RecipeForm) form: RecipeForm
|
||||||
|
|
||||||
|
recipe: Recipe
|
||||||
|
groups$ = this.groupService.all
|
||||||
|
units$ = new Subject<string>()
|
||||||
|
|
||||||
|
errorHandlers: ErrorHandler[] = [{
|
||||||
|
filter: error => error.type === 'notfound-recipe-id',
|
||||||
|
consumer: _ => this.urlUtils.navigateTo('/color/list')
|
||||||
|
}]
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private recipeService: RecipeService,
|
||||||
|
private companyService: CompanyService,
|
||||||
|
private groupService: GroupService,
|
||||||
|
private appState: AppState,
|
||||||
|
private alertService: AlertService,
|
||||||
|
errorService: ErrorService,
|
||||||
|
router: Router,
|
||||||
|
activatedRoute: ActivatedRoute
|
||||||
|
) {
|
||||||
|
super(errorService, activatedRoute, router)
|
||||||
|
|
||||||
|
this.fetchRecipe()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fetchRecipe() {
|
||||||
|
const recipeId = this.urlUtils.parseIntUrlParam('id')
|
||||||
|
this.subscribe(
|
||||||
|
this.recipeService.getById(recipeId),
|
||||||
|
recipe => {
|
||||||
|
this.recipe = recipe
|
||||||
|
this.appState.title = `${recipe.name} (Modifications)`
|
||||||
|
|
||||||
|
if (recipeMixCount(this.recipe) == 0) {
|
||||||
|
this.alertService.pushWarning('Il n\'y a aucun mélange dans cette recette')
|
||||||
|
}
|
||||||
|
if (recipeStepCount(this.recipe) == 0) {
|
||||||
|
this.alertService.pushWarning('Il n\'y a aucune étape dans cette recette')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
changeUnits(unit: string) {
|
||||||
|
this.units$.next(unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
const recipe = this.form.updatedRecipe
|
||||||
|
const steps = this.stepTable.mappedUpdatedSteps
|
||||||
|
|
||||||
|
if (!this.stepsPositionsAreValid(steps)) {
|
||||||
|
this.alertService.pushError('Les étapes ne peuvent pas avoir une position inférieure à 1')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subscribeAndNavigate(
|
||||||
|
this.recipeService.update(recipe, steps),
|
||||||
|
'/color/list'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete() {
|
||||||
|
this.subscribeAndNavigate(
|
||||||
|
this.recipeService.delete(this.recipe.id),
|
||||||
|
'/color/list'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
get loggedInUserGroupId(): number {
|
||||||
|
return this.appState.authenticatedUser.group?.id
|
||||||
|
}
|
||||||
|
|
||||||
|
private stepsPositionsAreValid(steps: Map<number, RecipeStep[]>): boolean {
|
||||||
|
return !anyMap(steps, (groupId, steps) => !!steps.find(s => s.position === 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -48,11 +48,10 @@ export class RecipeService {
|
||||||
return this.api.post<Recipe>('/recipe', body)
|
return this.api.post<Recipe>('/recipe', body)
|
||||||
}
|
}
|
||||||
|
|
||||||
update(id: number, name: string, description: string, color: string, gloss: number, sample: number, approbationDate: string, remark: string, steps: Map<number, RecipeStep[]>) {
|
update(recipe: Recipe, steps: Map<number, RecipeStep[]>) {
|
||||||
const body = {id, name, description, color, gloss, sample, remark, steps: []}
|
const body = {
|
||||||
if (approbationDate) {
|
...recipe,
|
||||||
// @ts-ignore
|
steps: []
|
||||||
body.approbationDate = approbationDate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
steps.forEach((groupSteps, groupId) => {
|
steps.forEach((groupSteps, groupId) => {
|
||||||
|
|
|
@ -156,11 +156,20 @@ export class CreComboBoxComponent implements OnInit {
|
||||||
next: entries => {
|
next: entries => {
|
||||||
this._entries = entries
|
this._entries = entries
|
||||||
|
|
||||||
this.internalControl.setValue(this.findEntryByKey(this.control.value)?.value)
|
if (this.control.value) {
|
||||||
|
this.internalControl.setValue(this.findEntryByKey(this.control.value)?.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.internalControl.disabled) {
|
||||||
|
this.internalControl.disable()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.internalControl = new FormControl(null, Validators.compose([this.control.validator, this.valueValidator()]))
|
this.internalControl = new FormControl({
|
||||||
|
value: null,
|
||||||
|
disabled: true
|
||||||
|
}, Validators.compose([this.control.validator, this.valueValidator()]))
|
||||||
this.internalControl.valueChanges.pipe(takeUntil(this._destroy$))
|
this.internalControl.valueChanges.pipe(takeUntil(this._destroy$))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: value => {
|
next: value => {
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
export function anyMap<K, V>(map: Map<K, V>, predicate: (key: K, value: V) => boolean): boolean {
|
||||||
|
return filterMap(map, predicate).size > 0
|
||||||
|
}
|
||||||
|
|
||||||
export function filterMap<K, V>(map: Map<K, V>, predicate: (key: K, value: V) => boolean): Map<K, V> {
|
export function filterMap<K, V>(map: Map<K, V>, predicate: (key: K, value: V) => boolean): Map<K, V> {
|
||||||
const filteredMap = new Map<K, V>()
|
const filteredMap = new Map<K, V>()
|
||||||
map.forEach((value, key) => {
|
map.forEach((value, key) => {
|
||||||
|
|
Loading…
Reference in New Issue