From 48e900f3c53cd0d5a9abaebf45cdc871adc65821 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Fri, 26 Mar 2021 15:48:18 -0400 Subject: [PATCH 1/4] Ajout du support des groupes dans la modification d'une recette. --- src/app/modules/colors/colors.module.ts | 4 +- .../step-table/step-table.component.html | 67 +++++++++++-- .../step-table/step-table.component.sass | 3 + .../step-table/step-table.component.ts | 97 ++++++++++++++++--- .../colors/pages/edit/edit.component.html | 11 ++- .../colors/pages/edit/edit.component.ts | 38 +++++++- .../pages/explore/explore.component.html | 6 +- .../colors/pages/explore/explore.component.ts | 2 +- .../modules/colors/services/recipe.service.ts | 13 ++- .../employees/pages/add/add.component.ts | 2 +- .../employees/pages/edit/edit.component.ts | 2 +- .../groups/pages/list/list.component.ts | 3 +- .../modules/groups/services/group.service.ts | 4 + .../permissions-list.component.ts | 1 + src/app/modules/shared/model/recipe.model.ts | 41 ++++++-- src/styles.sass | 9 ++ tsconfig.json | 2 +- 17 files changed, 256 insertions(+), 49 deletions(-) diff --git a/src/app/modules/colors/colors.module.ts b/src/app/modules/colors/colors.module.ts index 75a9ad1..6832ed8 100644 --- a/src/app/modules/colors/colors.module.ts +++ b/src/app/modules/colors/colors.module.ts @@ -18,6 +18,7 @@ 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({ @@ -29,7 +30,8 @@ import { MixesCardComponent } from './components/mixes-card/mixes-card.component ColorsRoutingModule, SharedModule, MatExpansionModule, - FormsModule + FormsModule, + MatSortModule ] }) export class ColorsModule { diff --git a/src/app/modules/colors/components/step-table/step-table.component.html b/src/app/modules/colors/components/step-table/step-table.component.html index 3922552..115f924 100644 --- a/src/app/modules/colors/components/step-table/step-table.component.html +++ b/src/app/modules/colors/components/step-table/step-table.component.html @@ -1,16 +1,63 @@ - - - Étapes - + + + Étapes + + + + Groupe + + + {{group.name}} + + + - +

Aucun groupe n'est sélectionné

+ + + + + + + +
- + + + + + + - + @@ -32,4 +79,4 @@
Position{{i + 1}}{{step.position}} + + + + + MessageContenu @@ -20,11 +67,11 @@ - + - +
-
+ diff --git a/src/app/modules/colors/components/step-table/step-table.component.sass b/src/app/modules/colors/components/step-table/step-table.component.sass index 44d6821..e34f3e9 100644 --- a/src/app/modules/colors/components/step-table/step-table.component.sass +++ b/src/app/modules/colors/components/step-table/step-table.component.sass @@ -1,5 +1,8 @@ mat-expansion-panel min-width: 560px + .empty-text + color: rgba(0, 0, 0, 0.54) + mat-form-field width: 20rem diff --git a/src/app/modules/colors/components/step-table/step-table.component.ts b/src/app/modules/colors/components/step-table/step-table.component.ts index f5e3a7e..3d92d34 100644 --- a/src/app/modules/colors/components/step-table/step-table.component.ts +++ b/src/app/modules/colors/components/step-table/step-table.component.ts @@ -1,6 +1,8 @@ -import {Component, Input, ViewChild} from '@angular/core'; -import {RecipeStep} from "../../../shared/model/recipe.model"; -import {MatTable} from "@angular/material/table"; +import {Component, Input} from '@angular/core' +import {Recipe, RecipeStep, recipeStepsForGroupId, sortRecipeSteps} from '../../../shared/model/recipe.model' +import {MatTable} from '@angular/material/table' +import {Observable} from 'rxjs' +import {EmployeeGroup} from '../../../shared/model/employee' @Component({ selector: 'cre-step-table', @@ -8,20 +10,89 @@ import {MatTable} from "@angular/material/table"; styleUrls: ['./step-table.component.sass'] }) export class StepTableComponent { - @ViewChild('stepTable', {static: true}) stepTable: MatTable - readonly columns = ['position', 'message', 'buttonRemove'] + readonly columns = ['position', 'buttonsPosition', 'message', 'buttonRemove'] - @Input() steps: RecipeStep[] + @Input() recipe: Recipe + @Input() groups$: Observable + @Input() selectedGroupId: number | null - hoveredStep : RecipeStep | null + hoveredStep: RecipeStep | null - addStep() { - this.steps.push({id: null, message: ""}) - this.stepTable.renderRows() + private groupSteps = new Map() + + addStep(table: MatTable) { + const addedStep = new RecipeStep(null, '', this.selectedGroupSteps.length + 1) + this.selectedGroupSteps.push(addedStep) + table.renderRows() } - removeStep(position: number) { - this.steps.splice(position, 1) - this.stepTable.renderRows() + removeStep(position: number, table: MatTable) { + this.selectedGroupSteps.splice(position, 1) + + // Decreases the position of each step above the removed one + for (let i = position; i < this.selectedGroupSteps.length; i++) { + this.selectedGroupSteps[i].position -= 1 + } + + table.renderRows() + } + + increasePosition(step: RecipeStep, table: MatTable) { + this.updateStepPosition(step, step.position + 1) + this.sort(table) + } + + decreasePosition(step: RecipeStep, table: MatTable) { + this.updateStepPosition(step, step.position - 1) + this.sort(table) + } + + sort(table: MatTable) { + this.groupSteps.set(this.selectedGroupId, sortRecipeSteps(this.selectedGroupSteps)) + table.renderRows() + } + + selectedGroupStepAtPosition(position: number): RecipeStep { + return this.selectedGroupSteps.find(s => s.position === position) + } + + selectedGroupHasStepAtPosition(position: number): boolean { + return this.selectedGroupStepAtPosition(position) != undefined + } + + get selectedGroupSteps(): RecipeStep[] { + if (!this.groupSteps.has(this.selectedGroupId)) { + this.groupSteps.set(this.selectedGroupId, recipeStepsForGroupId(this.recipe, this.selectedGroupId)) + } + return this.groupSteps.get(this.selectedGroupId) + } + + get selectedGroupStepsCount(): number { + return this.selectedGroupSteps.length + } + + get mappedUpdatedSteps(): Map { + const updatedStepsMap = new Map() + this.recipe.groupsInformation.forEach(i => { + updatedStepsMap.set(i.group.id, i.steps) + }) + + // Add steps for groups that were not already in the recipe + this.groupSteps.forEach((steps, groupId) => { + if (!updatedStepsMap.has(groupId)) { + updatedStepsMap.set(groupId, steps) + } + }) + return updatedStepsMap + } + + private updateStepPosition(step: RecipeStep, updatedPosition: number) { + if (!this.selectedGroupHasStepAtPosition(updatedPosition)) { + step.position = updatedPosition + } else { + const conflictingStep = this.selectedGroupStepAtPosition(updatedPosition) + conflictingStep.position = step.position + step.position = updatedPosition + } } } diff --git a/src/app/modules/colors/pages/edit/edit.component.html b/src/app/modules/colors/pages/edit/edit.component.html index 3d3705e..2ff1d65 100644 --- a/src/app/modules/colors/pages/edit/edit.component.html +++ b/src/app/modules/colors/pages/edit/edit.component.html @@ -3,7 +3,9 @@
- +
@@ -36,7 +38,12 @@
- + +
diff --git a/src/app/modules/colors/pages/edit/edit.component.ts b/src/app/modules/colors/pages/edit/edit.component.ts index c4f8a20..6b3acc6 100644 --- a/src/app/modules/colors/pages/edit/edit.component.ts +++ b/src/app/modules/colors/pages/edit/edit.component.ts @@ -1,6 +1,6 @@ import {Component, ViewChild} from '@angular/core' import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' -import {Recipe} from '../../../shared/model/recipe.model' +import {Recipe, RecipeStep} from '../../../shared/model/recipe.model' import {RecipeService} from '../../services/recipe.service' import {ActivatedRoute, Router} from '@angular/router' import {Validators} from '@angular/forms' @@ -12,6 +12,9 @@ import {EntityEditComponent} from '../../../shared/components/entity-edit/entity import {ImagesEditorComponent} from '../../components/images-editor/images-editor.component' import {ErrorModel, 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', @@ -24,6 +27,7 @@ export class EditComponent extends ErrorHandlingComponent { @ViewChild('imagesEditor') imagesEditor: ImagesEditorComponent recipe: Recipe | null + groups$ = this.groupService.all formFields = [ { name: 'name', @@ -108,8 +112,10 @@ export class EditComponent extends ErrorHandlingComponent { constructor( private recipeService: RecipeService, + private groupService: GroupService, private accountService: AccountService, private alertService: AlertService, + private appState: AppState, errorService: ErrorService, router: Router, activatedRoute: ActivatedRoute @@ -125,10 +131,10 @@ export class EditComponent extends ErrorHandlingComponent { parseInt(this.activatedRoute.snapshot.paramMap.get('id')), recipe => { this.recipe = recipe - if (this.recipe.mixes.length == 0) { + if (this.recipe.mixCount == 0) { this.alertService.pushWarning('Il n\'y a aucun mélange dans cette recette') } - if (this.recipe.steps.length == 0) { + if (this.recipe.stepCount == 0) { this.alertService.pushWarning('Il n\'y a aucune étape dans cette recette') } }, @@ -140,11 +146,18 @@ export class EditComponent extends ErrorHandlingComponent { this.units$.next(unit) } - submit(editComponent: EntityEditComponent) { + 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, this.recipe.steps), + this.recipeService.update(this.recipe.id, values.name, values.description, values.color, values.gloss, values.sample, values.approbationDate, values.remark, steps), '/color/list' ) } @@ -159,4 +172,19 @@ export class EditComponent extends ErrorHandlingComponent { get hasDeletePermission(): boolean { return this.accountService.hasPermission(EmployeePermission.REMOVE_RECIPE) } + + get loggedInEmployeeGroupId(): number { + return this.appState.authenticatedEmployee.group?.id + } + + private stepsPositionsAreValid(steps: Map): boolean { + let valid = true + steps.forEach((steps, _) => { + if (steps.find(s => s.position === 0)) { + valid = false + return + } + }) + return valid + } } diff --git a/src/app/modules/colors/pages/explore/explore.component.html b/src/app/modules/colors/pages/explore/explore.component.html index 39adb75..c516c0d 100644 --- a/src/app/modules/colors/pages/explore/explore.component.html +++ b/src/app/modules/colors/pages/explore/explore.component.html @@ -35,9 +35,9 @@
-
- -
+ + +
diff --git a/src/app/modules/colors/pages/explore/explore.component.ts b/src/app/modules/colors/pages/explore/explore.component.ts index 46bf6b9..958c8fe 100644 --- a/src/app/modules/colors/pages/explore/explore.component.ts +++ b/src/app/modules/colors/pages/explore/explore.component.ts @@ -55,7 +55,7 @@ export class ExploreComponent extends ErrorHandlingComponent { this.recipe = r this.note = r.note - if (this.recipe.mixes.length <= 0 || this.recipe.steps.length <= 0) { + if (this.recipe.mixCount <= 0 || this.recipe.stepCount <= 0) { this.alertService.pushWarning('Cette recette n\'est pas complète') } }, diff --git a/src/app/modules/colors/services/recipe.service.ts b/src/app/modules/colors/services/recipe.service.ts index 3f847d1..9eb2298 100644 --- a/src/app/modules/colors/services/recipe.service.ts +++ b/src/app/modules/colors/services/recipe.service.ts @@ -3,7 +3,6 @@ import {ApiService} from '../../shared/service/api.service' import {Observable} from 'rxjs' import {Recipe, RecipeStep} from '../../shared/model/recipe.model' import {map} from 'rxjs/operators' -import {MaterialQuantity} from '../../material/service/inventory.service' @Injectable({ providedIn: 'root' @@ -44,12 +43,20 @@ export class RecipeService { return this.api.post('/recipe', body) } - update(id: number, name: string, description: string, color: string, gloss: number, sample: number, approbationDate: string, remark: string, steps: RecipeStep[] = null) { - const body = {id, name, description, color, gloss, sample, remark, steps} + update(id: number, name: string, description: string, color: string, gloss: number, sample: number, approbationDate: string, remark: string, steps: Map) { + const body = {id, name, description, color, gloss, sample, remark, steps: []} if (approbationDate) { // @ts-ignore body.approbationDate = approbationDate } + + steps.forEach((groupSteps, groupId) => { + const mappedGroupSteps = groupSteps.map(s => { + return {message: s.message, position: s.position} + }) + body.steps.push({groupId, steps: mappedGroupSteps}) + }) + return this.api.put('/recipe', body) } diff --git a/src/app/modules/employees/pages/add/add.component.ts b/src/app/modules/employees/pages/add/add.component.ts index dd6e404..21f2d51 100644 --- a/src/app/modules/employees/pages/add/add.component.ts +++ b/src/app/modules/employees/pages/add/add.component.ts @@ -66,7 +66,7 @@ export class AddComponent extends ErrorHandlingComponent { icon: 'account-multiple', type: 'select', defaultValue: -1, - options$: this.groupService.all.pipe(map(groups => groups.map(g => { + options$: this.groupService.allWithDefault.pipe(map(groups => groups.map(g => { return {value: g.id, label: g.name} }))) }, { diff --git a/src/app/modules/employees/pages/edit/edit.component.ts b/src/app/modules/employees/pages/edit/edit.component.ts index 15b49a1..afa4023 100644 --- a/src/app/modules/employees/pages/edit/edit.component.ts +++ b/src/app/modules/employees/pages/edit/edit.component.ts @@ -49,7 +49,7 @@ export class EditComponent extends ErrorHandlingComponent { icon: 'account-multiple', type: 'select', valueFn: employee => employee.group ? employee.group.id : -1, - options$: this.groupService.all.pipe(map(groups => groups.map(g => { + options$: this.groupService.allWithDefault.pipe(map(groups => groups.map(g => { return {value: g.id, label: g.name} }))) }, { diff --git a/src/app/modules/groups/pages/list/list.component.ts b/src/app/modules/groups/pages/list/list.component.ts index e1a917a..93c9ded 100644 --- a/src/app/modules/groups/pages/list/list.component.ts +++ b/src/app/modules/groups/pages/list/list.component.ts @@ -1,7 +1,6 @@ import {Component} from '@angular/core' import {GroupService} from '../../services/group.service' import {EmployeeGroup, EmployeePermission} from '../../../shared/model/employee' -import {map} from 'rxjs/operators' import {AccountService} from '../../../accounts/services/account.service' import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' import {ActivatedRoute, Router} from '@angular/router' @@ -14,7 +13,7 @@ import {AlertService} from '../../../shared/service/alert.service' styleUrls: ['./list.component.sass'] }) export class ListComponent extends ErrorHandlingComponent { - groups$ = this.groupService.all.pipe(map(groups => groups.filter(g => g.id >= 0))) + groups$ = this.groupService.all defaultGroup: EmployeeGroup = null columns = [ {def: 'name', title: 'Nom', valueFn: g => g.name}, diff --git a/src/app/modules/groups/services/group.service.ts b/src/app/modules/groups/services/group.service.ts index fe56c48..565332c 100644 --- a/src/app/modules/groups/services/group.service.ts +++ b/src/app/modules/groups/services/group.service.ts @@ -15,6 +15,10 @@ export class GroupService { get all(): Observable { return this.api.get('/employee/group') + } + + get allWithDefault(): Observable { + return this.all .pipe(tap(groups => groups.unshift({ id: -1, name: 'Aucun', diff --git a/src/app/modules/shared/components/permissions-list/permissions-list.component.ts b/src/app/modules/shared/components/permissions-list/permissions-list.component.ts index 7595864..b63ac16 100644 --- a/src/app/modules/shared/components/permissions-list/permissions-list.component.ts +++ b/src/app/modules/shared/components/permissions-list/permissions-list.component.ts @@ -17,6 +17,7 @@ export class PermissionsListComponent { } get permissions(): EmployeePermission[] { + // @ts-ignore return this.filterPermissions(this.employee ? this.employee.permissions : this.group.permissions) } diff --git a/src/app/modules/shared/model/recipe.model.ts b/src/app/modules/shared/model/recipe.model.ts index 16dc864..679ba1a 100644 --- a/src/app/modules/shared/model/recipe.model.ts +++ b/src/app/modules/shared/model/recipe.model.ts @@ -1,6 +1,7 @@ -import {Material} from "./material.model"; -import {LocalDate} from "js-joda"; -import {Company} from "./company.model"; +import {Material} from './material.model' +import {LocalDate} from 'js-joda' +import {Company} from './company.model' +import {EmployeeGroup} from './employee' export class Recipe { constructor( @@ -12,9 +13,26 @@ export class Recipe { public sample: number, public approbationDate: LocalDate, public remark: string, - public note: string, public company: Company, public mixes: Mix[], + public groupsInformation: RecipeGroupInformation[] + ) { + } + + get mixCount(): number { + return this.mixes.length + } + + get stepCount(): number { + return this.groupsInformation.flatMap(i => i.steps).length + } +} + +export class RecipeGroupInformation { + constructor( + public id: number, + public group: EmployeeGroup, + public note: string, public steps: RecipeStep[] ) { } @@ -34,7 +52,8 @@ export class MixMaterial { constructor( public id: number, public material: Material, - public quantity: number + public quantity: number, + public position: number ) { } } @@ -51,7 +70,17 @@ class MixType { export class RecipeStep { constructor( public id: number, - public message: string + public message: string, + public position: number ) { } } + +export function recipeStepsForGroupId(recipe: Recipe, groupId: number): RecipeStep[] { + const groupInformation = recipe.groupsInformation.find(i => i.group.id === groupId) + return groupInformation ? sortRecipeSteps(groupInformation.steps) : [] +} + +export function sortRecipeSteps(steps: RecipeStep[]): RecipeStep[] { + return steps.sort((a, b) => a.position - b.position) +} diff --git a/src/styles.sass b/src/styles.sass index 2e6f3f5..d51f3b8 100644 --- a/src/styles.sass +++ b/src/styles.sass @@ -85,6 +85,15 @@ mat-expansion-panel.table-title &:hover, &:focus background-color: $color-primary !important + &.header-field .mat-form-field-flex + background-color: white + + .mat-form-field-outline + opacity: 1 + + &:first-child + opacity: 0 + mat-panel-title color: $light-primary-text !important font-weight: bold diff --git a/tsconfig.json b/tsconfig.json index 8c4ef3b..fcea47f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ "importHelpers": true, "target": "es2015", "lib": [ - "es2018", + "es2019", "dom" ] }, From 3f0be111e3c33527edf4e1479ca6ba2dc7bcdd7d Mon Sep 17 00:00:00 2001 From: FyloZ Date: Fri, 26 Mar 2021 16:40:27 -0400 Subject: [PATCH 2/4] Ajout du support des groupes dans l'explorateur de recette. --- .../step-list/step-list.component.html | 7 ++- .../step-list/step-list.component.ts | 9 +++- .../step-table/step-table.component.sass | 3 -- .../pages/explore/explore.component.html | 30 ++++++++--- .../colors/pages/explore/explore.component.ts | 54 +++++++++++++++---- .../modules/colors/services/recipe.service.ts | 17 ++++-- src/app/modules/shared/model/recipe.model.ts | 6 +++ src/styles.sass | 3 ++ 8 files changed, 100 insertions(+), 29 deletions(-) diff --git a/src/app/modules/colors/components/step-list/step-list.component.html b/src/app/modules/colors/components/step-list/step-list.component.html index ff972e2..f514e70 100644 --- a/src/app/modules/colors/components/step-list/step-list.component.html +++ b/src/app/modules/colors/components/step-list/step-list.component.html @@ -4,9 +4,12 @@ - - {{i + 1}}.{{step.message}} + + {{step.position}}.{{step.message}} + +

Aucun groupe n'est sélectionné

+

Il n'y a aucune étape définie pour ce groupe

diff --git a/src/app/modules/colors/components/step-list/step-list.component.ts b/src/app/modules/colors/components/step-list/step-list.component.ts index 79666f6..4c7ddb2 100644 --- a/src/app/modules/colors/components/step-list/step-list.component.ts +++ b/src/app/modules/colors/components/step-list/step-list.component.ts @@ -1,5 +1,5 @@ import {Component, Input} from '@angular/core'; -import {RecipeStep} from "../../../shared/model/recipe.model"; +import {Recipe, RecipeStep, recipeStepsForGroupId} from '../../../shared/model/recipe.model' @Component({ selector: 'cre-step-list', @@ -7,5 +7,10 @@ import {RecipeStep} from "../../../shared/model/recipe.model"; styleUrls: ['./step-list.component.sass'] }) export class StepListComponent { - @Input() steps: RecipeStep[] + @Input() recipe: Recipe + @Input() selectedGroupId: number | null + + get steps(): RecipeStep[] { + return recipeStepsForGroupId(this.recipe, this.selectedGroupId) + } } diff --git a/src/app/modules/colors/components/step-table/step-table.component.sass b/src/app/modules/colors/components/step-table/step-table.component.sass index e34f3e9..44d6821 100644 --- a/src/app/modules/colors/components/step-table/step-table.component.sass +++ b/src/app/modules/colors/components/step-table/step-table.component.sass @@ -1,8 +1,5 @@ mat-expansion-panel min-width: 560px - .empty-text - color: rgba(0, 0, 0, 0.54) - mat-form-field width: 20rem diff --git a/src/app/modules/colors/pages/explore/explore.component.html b/src/app/modules/colors/pages/explore/explore.component.html index c516c0d..0a98562 100644 --- a/src/app/modules/colors/pages/explore/explore.component.html +++ b/src/app/modules/colors/pages/explore/explore.component.html @@ -10,14 +10,30 @@ Enregistrer
- + +
+ + + Groupe + + + {{group.name}} + + + +
Note - + @@ -35,13 +51,13 @@ - - - +
+ +
-
- +
+
diff --git a/src/app/modules/colors/pages/explore/explore.component.ts b/src/app/modules/colors/pages/explore/explore.component.ts index 958c8fe..591560b 100644 --- a/src/app/modules/colors/pages/explore/explore.component.ts +++ b/src/app/modules/colors/pages/explore/explore.component.ts @@ -2,13 +2,15 @@ import {Component} from '@angular/core' import {RecipeService} from '../../services/recipe.service' import {ActivatedRoute, Router} from '@angular/router' import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' -import {Recipe} from '../../../shared/model/recipe.model' +import {Recipe, recipeNoteForGroupId} from '../../../shared/model/recipe.model' import {Observable, Subject} from 'rxjs' import {ErrorModel, ErrorService} from '../../../shared/service/error.service' import {AlertService} from '../../../shared/service/alert.service' import {GlobalAlertHandlerComponent} from '../../../shared/components/global-alert-handler/global-alert-handler.component' import {InventoryService} from '../../../material/service/inventory.service' import {ConfirmBoxComponent} from '../../../shared/components/confirm-box/confirm-box.component' +import {GroupService} from '../../../groups/services/group.service' +import {AppState} from '../../../shared/app-state' @Component({ selector: 'cre-explore', @@ -17,13 +19,15 @@ import {ConfirmBoxComponent} from '../../../shared/components/confirm-box/confir }) export class ExploreComponent extends ErrorHandlingComponent { recipe: Recipe | null + groups$ = this.groupService.all deductErrorBody = {} units$ = new Subject() + selectedGroupId: number | null hasModifications = false - note: string | null quantitiesChanges = new Map>() mixesLocationChanges = new Map() + groupsNote = new Map() deductedMixId: number | null handledErrorModels: ErrorModel[] = [{ @@ -35,7 +39,9 @@ export class ExploreComponent extends ErrorHandlingComponent { constructor( private recipeService: RecipeService, private inventoryService: InventoryService, + private groupService: GroupService, private alertService: AlertService, + private appState: AppState, errorService: ErrorService, router: Router, activatedRoute: ActivatedRoute @@ -47,13 +53,14 @@ export class ExploreComponent extends ErrorHandlingComponent { super.ngOnInit() GlobalAlertHandlerComponent.extraTopMarginMultiplier = 2.5 + this.selectedGroupId = this.loggedInEmployeeGroupId + const id = parseInt(this.activatedRoute.snapshot.paramMap.get('id')) this.subscribeEntityById( this.recipeService, id, r => { this.recipe = r - this.note = r.note if (this.recipe.mixCount <= 0 || this.recipe.stepCount <= 0) { this.alertService.pushWarning('Cette recette n\'est pas complète') @@ -72,11 +79,6 @@ export class ExploreComponent extends ErrorHandlingComponent { this.units$.next(unit) } - changeNote(event: any) { - this.hasModifications = true - this.note = event.target.value - } - changeQuantity(event: { id: number, materialId: number, quantity: number }) { if (!this.quantitiesChanges.has(event.id)) { this.quantitiesChanges.set(event.id, new Map()) @@ -91,8 +93,11 @@ export class ExploreComponent extends ErrorHandlingComponent { saveModifications() { this.subscribe( - this.recipeService.saveExplorerModifications(this.recipe.id, this.note, this.mixesLocationChanges), - () => this.alertService.pushSuccess('Les modifications ont été enregistrées'), + this.recipeService.updateExplorerModifications(this.recipe.id, this.mappedUpdatedNotes, this.mixesLocationChanges), + () => { + this.hasModifications = false + this.alertService.pushSuccess('Les modifications ont été enregistrées') + }, true ) } @@ -120,4 +125,33 @@ export class ExploreComponent extends ErrorHandlingComponent { true ) } + + get loggedInEmployeeGroupId(): number { + return this.appState.authenticatedEmployee.group?.id + } + + get selectedGroupNote(): string { + if (!this.groupsNote.has(this.selectedGroupId)) { + this.groupsNote.set(this.selectedGroupId, recipeNoteForGroupId(this.recipe, this.selectedGroupId)) + } + return this.groupsNote.get(this.selectedGroupId) + } + + set selectedGroupNote(value: string) { + this.groupsNote.set(this.selectedGroupId, value) + } + + private get mappedUpdatedNotes(): Map { + const updatedNotes = new Map() + + this.recipe.groupsInformation.forEach(i => { + updatedNotes.set(i.group.id, i.note) + }) + + this.groupsNote.forEach((content, groupId) => { + updatedNotes.set(groupId, content) + }) + + return updatedNotes + } } diff --git a/src/app/modules/colors/services/recipe.service.ts b/src/app/modules/colors/services/recipe.service.ts index 9eb2298..5e80f25 100644 --- a/src/app/modules/colors/services/recipe.service.ts +++ b/src/app/modules/colors/services/recipe.service.ts @@ -60,13 +60,20 @@ export class RecipeService { return this.api.put('/recipe', body) } - saveExplorerModifications(id: number, note: string, mixesLocationChange: Map): Observable { + updateExplorerModifications(id: number, notes: Map, mixesLocationChange: Map): Observable { const body = { - id, - note, - mixesLocation: {} + recipeId: id, + notes: [], + mixesLocation: [] } - mixesLocationChange.forEach((l, i) => body.mixesLocation[i] = l) + + notes.forEach((content, groupId) => { + body.notes.push({groupId, content}) + }) + + mixesLocationChange.forEach((location, mixId) => { + body.mixesLocation.push({mixId, location}) + }) return this.api.put('/recipe/public', body) } diff --git a/src/app/modules/shared/model/recipe.model.ts b/src/app/modules/shared/model/recipe.model.ts index 679ba1a..4eff8c2 100644 --- a/src/app/modules/shared/model/recipe.model.ts +++ b/src/app/modules/shared/model/recipe.model.ts @@ -76,6 +76,11 @@ export class RecipeStep { } } +export function recipeNoteForGroupId(recipe: Recipe, groupId: number): string | null { + const groupInformation = recipe.groupsInformation.find(i => i.group.id === groupId) + return groupInformation ? groupInformation.note : null +} + export function recipeStepsForGroupId(recipe: Recipe, groupId: number): RecipeStep[] { const groupInformation = recipe.groupsInformation.find(i => i.group.id === groupId) return groupInformation ? sortRecipeSteps(groupInformation.steps) : [] @@ -84,3 +89,4 @@ export function recipeStepsForGroupId(recipe: Recipe, groupId: number): RecipeSt export function sortRecipeSteps(steps: RecipeStep[]): RecipeStep[] { return steps.sort((a, b) => a.position - b.position) } + diff --git a/src/styles.sass b/src/styles.sass index d51f3b8..bfdaa80 100644 --- a/src/styles.sass +++ b/src/styles.sass @@ -191,6 +191,9 @@ div.empty .alert p margin-bottom: 0 +.empty-text + color: rgba(0, 0, 0, 0.54) + .dark-background position: fixed width: 100% From 3d14432b930e403d99ef6b1cef86a1a103dd25df Mon Sep 17 00:00:00 2001 From: FyloZ Date: Mon, 29 Mar 2021 19:55:07 -0400 Subject: [PATCH 3/4] =?UTF-8?q?Ajout=20du=20support=20pour=20la=20position?= =?UTF-8?q?=20des=20ingr=C3=A9dients=20dans=20un=20m=C3=A9lange.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mix-editor/mix-editor.component.html | 35 ++++++-- .../mix-editor/mix-editor.component.sass | 3 + .../mix-editor/mix-editor.component.ts | 88 +++++++++++-------- .../mix-table/mix-table.component.html | 28 +++--- .../mix-table/mix-table.component.ts | 64 +++++++------- .../mixes-card/mixes-card.component.html | 2 +- .../mixes-card/mixes-card.component.ts | 4 +- .../colors/pages/explore/explore.component.ts | 10 +-- .../pages/mix/mix-edit/mix-edit.component.ts | 12 +++ .../modules/colors/services/mix.service.ts | 49 +++++------ src/app/modules/shared/model/recipe.model.ts | 23 +++++ src/app/modules/shared/units.ts | 6 +- 12 files changed, 206 insertions(+), 118 deletions(-) diff --git a/src/app/modules/colors/components/mix-editor/mix-editor.component.html b/src/app/modules/colors/components/mix-editor/mix-editor.component.html index f5c2d65..1c1ca94 100644 --- a/src/app/modules/colors/components/mix-editor/mix-editor.component.html +++ b/src/app/modules/colors/components/mix-editor/mix-editor.component.html @@ -28,17 +28,42 @@ - + - +
+ + + + + @@ -67,10 +92,10 @@
Position + {{mixMaterial.position}} + - {{i + 1}} + + + + Unités - +

%

- + {{units}} diff --git a/src/app/modules/colors/components/mix-editor/mix-editor.component.sass b/src/app/modules/colors/components/mix-editor/mix-editor.component.sass index ee4dba4..3eb5b9b 100644 --- a/src/app/modules/colors/components/mix-editor/mix-editor.component.sass +++ b/src/app/modules/colors/components/mix-editor/mix-editor.component.sass @@ -1,3 +1,6 @@ +mat-card + max-width: unset !important + td.units-wrapper p width: 3rem margin-bottom: 0 diff --git a/src/app/modules/colors/components/mix-editor/mix-editor.component.ts b/src/app/modules/colors/components/mix-editor/mix-editor.component.ts index cab63ae..0aa425f 100644 --- a/src/app/modules/colors/components/mix-editor/mix-editor.component.ts +++ b/src/app/modules/colors/components/mix-editor/mix-editor.component.ts @@ -1,12 +1,17 @@ import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core' -import {Mix, MixMaterial, Recipe} from '../../../shared/model/recipe.model' +import { + Mix, + MixMaterial, + MixMaterialDto, + mixMaterialsAsMixMaterialsDto, + Recipe, RecipeStep, + sortMixMaterialsDto +} from '../../../shared/model/recipe.model' import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' import {MixService} from '../../services/mix.service' -import {Observable} from 'rxjs' import {RecipeService} from '../../services/recipe.service' import {Material} from '../../../shared/model/material.model' import {MaterialService} from '../../../material/service/material.service' -import {MaterialType} from '../../../shared/model/materialtype.model' import {MaterialTypeService} from '../../../material-type/service/material-type.service' import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms' import {UNIT_MILLILITER} from '../../../shared/units' @@ -24,7 +29,7 @@ import {MatSelect} from '@angular/material/select' styleUrls: ['./mix-editor.component.sass'] }) export class MixEditorComponent extends ErrorHandlingComponent { - @ViewChild('mixTable') mixTable: MatTable + @ViewChild('matTable') mixTable: MatTable @ViewChild('deleteConfirmBox') deleteConfirmBox: ConfirmBoxComponent @Input() mixId: number | null @@ -35,24 +40,24 @@ export class MixEditorComponent extends ErrorHandlingComponent { mix: Mix | null recipe: Recipe | null - materialTypes$: Observable + materialTypes$ = this.materialTypeService.all form: FormGroup nameControl: FormControl materialTypeControl: FormControl - mixMaterials = [] + mixMaterials: MixMaterialDto[] = [] editionMode = false units = UNIT_MILLILITER hoveredMixMaterial: MixMaterial | null - columns = ['position', 'material', 'quantity', 'units', 'buttonRemove'] + columns = ['position', 'buttonsPosition', 'material', 'quantity', 'units', 'buttonRemove'] deleting = false handledErrorModels = [{ filter: error => error.status === 409 && !this.deleting, messageProducer: error => `Un mélange avec le nom '${error.id}' existe déjà dans cette recette` }, { - filter: error => error.error.status === 409 && this.deleting, + filter: error => error.error && error.error.status === 409 && this.deleting, consumer: () => this.deleting = false, messageProducer: () => 'Ce mélange est utilisé par un ou plusieurs autres mélanges' }] @@ -85,28 +90,19 @@ export class MixEditorComponent extends ErrorHandlingComponent { r => { this.recipe = r if (this.editionMode) { - this.subscribeEntityById( - this.mixService, - this.mixId, - m => { - this.mix = m - this.mixMaterials = this.mixService.extractMixMaterials(this.mix) - this.generateForm() - }, - '/color/list' - ) + this.mix = this.recipe.mixes.find(m => m.id === this.mixId) + this.mixMaterials = mixMaterialsAsMixMaterialsDto(this.mix) } else { - this.mixMaterials.push({}) - this.generateForm() + this.addBlankMixMaterial() } + this.generateForm() }, '/color/list' ) - this.materialTypes$ = this.materialTypeService.all } addRow() { - this.mixMaterials.push({materialId: null, quantity: null, percents: false}) + this.addBlankMixMaterial() this.mixTable.renderRows() } @@ -115,6 +111,21 @@ export class MixEditorComponent extends ErrorHandlingComponent { this.mixTable.renderRows() } + increasePosition(mixMaterial: MixMaterialDto, table: MatTable) { + this.updateMixMaterialPosition(mixMaterial, mixMaterial.position + 1) + this.sort(table) + } + + decreasePosition(mixMaterial: MixMaterialDto, table: MatTable) { + this.updateMixMaterialPosition(mixMaterial, mixMaterial.position - 1) + this.sort(table) + } + + sort(table: MatTable) { + this.mixMaterials = sortMixMaterialsDto(this.mixMaterials) + table.renderRows() + } + submit() { this.save.emit({ name: this.nameControl.value, @@ -130,19 +141,6 @@ export class MixEditorComponent extends ErrorHandlingComponent { this.subscribeAndNavigate(this.mixService.delete(this.mixId), `/color/edit/${this.recipeId}`) } - materialUsePercentages(mixMaterial: any) { - if (!mixMaterial.materialId) { - return null - } - const material = this.getMaterialFromId(mixMaterial.materialId) - mixMaterial.percents = material && material.materialType.usePercentages - return mixMaterial.percents - } - - getMaterialFromId(id: number): Material { - return id ? this.materials.filter(m => m.id === id)[0] : null - } - getAvailableMaterials(selector: MatSelect): Material[] { return this.materials.filter(m => selector.value === m.id || this.mixMaterials.filter(mm => mm.materialId === m.id).length === 0) } @@ -159,4 +157,24 @@ export class MixEditorComponent extends ErrorHandlingComponent { materialType: this.materialTypeControl }) } + + private addBlankMixMaterial() { + this.mixMaterials.push( + new MixMaterialDto(null, 0, false, this.mixMaterials.length + 1) + ) + } + + private updateMixMaterialPosition(mixMaterial: MixMaterialDto, updatedPosition: number) { + if (!this.mixMaterialAtPosition(updatedPosition)) { + mixMaterial.position = updatedPosition + } else { + const conflictingStep = this.mixMaterialAtPosition(updatedPosition) + conflictingStep.position = mixMaterial.position + mixMaterial.position = updatedPosition + } + } + + private mixMaterialAtPosition(position: number): MixMaterialDto { + return this.mixMaterials.find(m => m.position === position) + } } diff --git a/src/app/modules/colors/components/mix-table/mix-table.component.html b/src/app/modules/colors/components/mix-table/mix-table.component.html index 10f11c0..a10fd91 100644 --- a/src/app/modules/colors/components/mix-table/mix-table.component.html +++ b/src/app/modules/colors/components/mix-table/mix-table.component.html @@ -33,16 +33,22 @@ - +
+ + + + + + - + - + @@ -55,8 +61,8 @@ type="number" min="0.001" step="0.001" - [value]="getComputedQuantityRounded(mixMaterial)" - [disabled]="mixMaterial.material.materialType.usePercentages" + [value]="getMixMaterialQuantityRounded(mixMaterial)" + [disabled]="mixMaterial.isPercents" (keyup)="changeQuantity($event, mixMaterial)"/> @@ -76,12 +82,12 @@ - + - @@ -89,8 +95,8 @@ @@ -103,7 +109,7 @@ @@ -115,7 +121,7 @@ diff --git a/src/app/modules/colors/components/mix-table/mix-table.component.ts b/src/app/modules/colors/components/mix-table/mix-table.component.ts index bb67518..8a31b9f 100644 --- a/src/app/modules/colors/components/mix-table/mix-table.component.ts +++ b/src/app/modules/colors/components/mix-table/mix-table.component.ts @@ -1,5 +1,5 @@ import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core' -import {Mix, MixMaterial, Recipe} from '../../../shared/model/recipe.model' +import {Mix, MixMaterial, MixMaterialDto, mixMaterialsAsMixMaterialsDto, Recipe} from '../../../shared/model/recipe.model' import {Subject} from 'rxjs' import {SubscribingComponent} from '../../../shared/components/subscribing.component' import {convertMixMaterialQuantity, UNIT_MILLILITER} from '../../../shared/units' @@ -18,7 +18,7 @@ import {MaterialService} from '../../../material/service/material.service' }) export class MixTableComponent extends SubscribingComponent { private readonly COLUMNS = ['material', 'materialType', 'quantity', 'quantityCalculated', 'quantityUnits', 'simdut'] - private readonly COLUMNS_STATIC = ['material', 'materialType', 'quantityStatic', 'quantityUnits'] + private readonly COLUMNS_EDIT = ['position', 'material', 'materialType', 'quantityStatic', 'quantityUnits'] @ViewChild('printingConfirmBox') printingConfirmBox: ConfirmBoxComponent @@ -28,13 +28,13 @@ export class MixTableComponent extends SubscribingComponent { @Input() deductErrorBody @Input() editionMode: boolean @Output() locationChange = new EventEmitter<{ id: number, location: string }>() - @Output() quantityChange = new EventEmitter<{ id: number, materialId: number, quantity: number }>() + @Output() quantityChange = new EventEmitter() @Output() deduct = new EventEmitter() @Output() printingErrorChange = new EventEmitter() mixColumns = this.COLUMNS units = UNIT_MILLILITER - computedQuantities: { id: number, percents: boolean, quantity: number }[] = [] + mixMaterials: MixMaterialDto[] = [] hoveredMixMaterial: MixMaterial | null hasSimdutMap: any = {} @@ -55,23 +55,19 @@ export class MixTableComponent extends SubscribingComponent { super.ngOnInit() if (this.editionMode) { - this.mixColumns = this.COLUMNS_STATIC + this.mixColumns = this.COLUMNS_EDIT } - this.mix.mixMaterials.forEach(m => this.computedQuantities.push({ - id: m.id, - percents: m.material.materialType.usePercentages, - quantity: m.quantity - })) + this.mixMaterials = mixMaterialsAsMixMaterialsDto(this.mix) this.subscribe( this.units$, u => this.convertQuantities(u) ) - this.mix.mixMaterials.map(mm => mm.material).forEach(material => this.subscribe( - this.materialService.hasSimdut(material.id), - b => this.hasSimdutMap[material.id] = b + this.mixMaterials.forEach(mixMaterial => this.subscribe( + this.materialService.hasSimdut(mixMaterial.materialId), + b => this.hasSimdutMap[mixMaterial.materialId] = b ) ) } @@ -84,26 +80,30 @@ export class MixTableComponent extends SubscribingComponent { const newQuantity = parseInt(event.target.value) let ratio = 1 if (!isTotal) { - const originalQuantity = this.getComputedQuantity(mixMaterial.id) + const originalQuantity = this.findMixMaterialDto(mixMaterial.material.id) ratio = newQuantity / originalQuantity.quantity } else { ratio = newQuantity / this.getTotalQuantity() } - this.computedQuantities.forEach((q, i) => { - if (!q.percents) { + this.mixMaterials.forEach((q, i) => { + if (!q.isPercents) { q.quantity *= ratio } this.emitQuantityChangeEvent(i) }) } - getComputedQuantityRounded(mixMaterial: MixMaterial): number { - return this.round(this.getComputedQuantity(mixMaterial.id).quantity) + getMixMaterialFromDto(mixMaterialDto: MixMaterialDto): MixMaterial { + return this.mix.mixMaterials.find(m => m.material.id === mixMaterialDto.materialId) + } + + getMixMaterialQuantityRounded(mixMaterial: MixMaterialDto): number { + return this.round(this.getMixMaterialFromDto(this.findMixMaterialDto(mixMaterial.materialId)).quantity) } getTotalQuantity(index: number = -1): number { if (index === -1) { - index = this.computedQuantities.length - 1 + index = this.mixMaterials.length - 1 } let totalQuantity = 0 for (let i = 0; i <= index; i++) { @@ -112,7 +112,7 @@ export class MixTableComponent extends SubscribingComponent { return totalQuantity } - getCalculatedQuantity(mixMaterial: MixMaterial, index: number): string { + getCalculatedQuantityHtml(mixMaterial: MixMaterial, index: number): string { const totalQuantity = this.round(this.getTotalQuantity(index)) const addedQuantity = this.round(this.calculateQuantity(index)) return `+${addedQuantity} (${totalQuantity})` @@ -127,8 +127,8 @@ export class MixTableComponent extends SubscribingComponent { return Math.round(quantity * 1000) / 1000 } - openSimdutFile(mixMaterial: MixMaterial) { - window.open(`${environment.apiUrl}/material/${mixMaterial.material.id}/simdut`, '_blank') + openSimdutFile(mixMaterial: MixMaterialDto) { + window.open(`${environment.apiUrl}/material/${mixMaterial.materialId}/simdut`, '_blank') } async print() { @@ -169,28 +169,30 @@ export class MixTableComponent extends SubscribingComponent { } private emitQuantityChangeEvent(index: number) { + const quantity = this.mixMaterials[index] this.quantityChange.emit({ - id: this.mix.id, - materialId: this.computedQuantities[index].id, - quantity: this.calculateQuantity(index) + materialId: quantity.materialId, + quantity: this.calculateQuantity(index), + isPercents: quantity.isPercents, + position: quantity.position }) } private convertQuantities(newUnit: string) { - this.computedQuantities.forEach(q => q.quantity = convertMixMaterialQuantity(q, this.units, newUnit)) + this.mixMaterials.forEach(q => q.quantity = convertMixMaterialQuantity(q, this.units, newUnit)) this.units = newUnit } - private getComputedQuantity(id: number): any { - return this.computedQuantities.filter(q => q.id == id)[0] + private findMixMaterialDto(materialId: number): MixMaterialDto { + return this.mixMaterials.find(q => q.materialId == materialId) } private calculateQuantity(index: number): number { - const computedQuantity = this.computedQuantities[index] - if (!computedQuantity.percents) { + const computedQuantity = this.mixMaterials[index] + if (!computedQuantity.isPercents) { return computedQuantity.quantity } - return this.computedQuantities[0].quantity * (computedQuantity.quantity / 100) + return this.mixMaterials[0].quantity * (computedQuantity.quantity / 100) } } diff --git a/src/app/modules/colors/components/mixes-card/mixes-card.component.html b/src/app/modules/colors/components/mixes-card/mixes-card.component.html index 0c8ffeb..b6766df 100644 --- a/src/app/modules/colors/components/mixes-card/mixes-card.component.html +++ b/src/app/modules/colors/components/mixes-card/mixes-card.component.html @@ -11,7 +11,7 @@ [units$]="units$" [deductErrorBody]="deductErrorBody" [editionMode]="editionMode" - (quantityChange)="quantityChange.emit($event)" + (quantityChange)="quantityChange.emit({mixId: mix.id, mixMaterial: $event})" (locationChange)="locationChange.emit($event)" (deduct)="deduct.emit(mix.id)"> diff --git a/src/app/modules/colors/components/mixes-card/mixes-card.component.ts b/src/app/modules/colors/components/mixes-card/mixes-card.component.ts index 920132a..b775dec 100644 --- a/src/app/modules/colors/components/mixes-card/mixes-card.component.ts +++ b/src/app/modules/colors/components/mixes-card/mixes-card.component.ts @@ -1,5 +1,5 @@ import {Component, EventEmitter, Input, Output} from '@angular/core'; -import {Recipe} from "../../../shared/model/recipe.model"; +import {MixMaterialDto, Recipe} from '../../../shared/model/recipe.model' import {Subject} from "rxjs"; @Component({ @@ -14,7 +14,7 @@ export class MixesCardComponent { @Input() editionMode = false @Output() locationChange = new EventEmitter<{ id: number, location: string }>() - @Output() quantityChange = new EventEmitter<{ id: number, materialId: number, quantity: number }>() + @Output() quantityChange = new EventEmitter<{ mixId: number, mixMaterial: MixMaterialDto}>() @Output() deduct = new EventEmitter() @Output() printingErrorChange = new EventEmitter() } diff --git a/src/app/modules/colors/pages/explore/explore.component.ts b/src/app/modules/colors/pages/explore/explore.component.ts index 591560b..a83add8 100644 --- a/src/app/modules/colors/pages/explore/explore.component.ts +++ b/src/app/modules/colors/pages/explore/explore.component.ts @@ -2,7 +2,7 @@ import {Component} from '@angular/core' import {RecipeService} from '../../services/recipe.service' import {ActivatedRoute, Router} from '@angular/router' import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' -import {Recipe, recipeNoteForGroupId} from '../../../shared/model/recipe.model' +import {MixMaterialDto, Recipe, recipeNoteForGroupId} from '../../../shared/model/recipe.model' import {Observable, Subject} from 'rxjs' import {ErrorModel, ErrorService} from '../../../shared/service/error.service' import {AlertService} from '../../../shared/service/alert.service' @@ -79,11 +79,11 @@ export class ExploreComponent extends ErrorHandlingComponent { this.units$.next(unit) } - changeQuantity(event: { id: number, materialId: number, quantity: number }) { - if (!this.quantitiesChanges.has(event.id)) { - this.quantitiesChanges.set(event.id, new Map()) + changeQuantity(event: { mixId: number, mixMaterial: MixMaterialDto}) { + if (!this.quantitiesChanges.has(event.mixId)) { + this.quantitiesChanges.set(event.mixId, new Map()) } - this.quantitiesChanges.get(event.id).set(event.materialId, event.quantity) + this.quantitiesChanges.get(event.mixId).set(event.mixMaterial.materialId, event.mixMaterial.quantity) } changeMixLocation(event: { id: number, location: string }) { diff --git a/src/app/modules/colors/pages/mix/mix-edit/mix-edit.component.ts b/src/app/modules/colors/pages/mix/mix-edit/mix-edit.component.ts index f463f5f..b80d096 100644 --- a/src/app/modules/colors/pages/mix/mix-edit/mix-edit.component.ts +++ b/src/app/modules/colors/pages/mix/mix-edit/mix-edit.component.ts @@ -5,6 +5,8 @@ import {Material} from '../../../../shared/model/material.model' import {MaterialService} from '../../../../material/service/material.service' import {MixService} from '../../../services/mix.service' import {ErrorModel, ErrorService} from '../../../../shared/service/error.service' +import {MixMaterialDto} from '../../../../shared/model/recipe.model' +import {AlertService} from '../../../../shared/service/alert.service' @Component({ selector: 'cre-mix-edit', @@ -21,6 +23,7 @@ export class MixEditComponent extends ErrorHandlingComponent { constructor( private materialService: MaterialService, private mixService: MixService, + private alertService: AlertService, errorService: ErrorService, router: Router, activatedRoute: ActivatedRoute @@ -41,9 +44,18 @@ export class MixEditComponent extends ErrorHandlingComponent { } submit(values) { + if(!this.mixMaterialsPositionAreValid(values.mixMaterials)) { + this.alertService.pushError('Les ingrédients ne peuvent pas avoir une position inférieure à 1') + return + } + this.subscribeAndNavigate( this.mixService.updateWithUnits(this.mixId, values.name, values.materialTypeId, values.mixMaterials, values.units), `/color/edit/${this.recipeId}` ) } + + private mixMaterialsPositionAreValid(mixMaterials: MixMaterialDto[]): boolean { + return !mixMaterials.find(m => m.position <= 0) + } } diff --git a/src/app/modules/colors/services/mix.service.ts b/src/app/modules/colors/services/mix.service.ts index a27b0cd..cfd57bf 100644 --- a/src/app/modules/colors/services/mix.service.ts +++ b/src/app/modules/colors/services/mix.service.ts @@ -1,8 +1,8 @@ -import {Injectable} from '@angular/core'; -import {ApiService} from "../../shared/service/api.service"; -import {convertMixMaterialQuantity, UNIT_MILLILITER} from "../../shared/units"; -import {Observable} from "rxjs"; -import {Mix} from "../../shared/model/recipe.model"; +import {Injectable} from '@angular/core' +import {ApiService} from '../../shared/service/api.service' +import {convertMixMaterialQuantity, UNIT_MILLILITER} from '../../shared/units' +import {Observable} from 'rxjs' +import {Mix, MixMaterialDto} from '../../shared/model/recipe.model' @Injectable({ providedIn: 'root' @@ -21,32 +21,33 @@ export class MixService { return this.api.get(`/recipe/mix/${id}`) } - saveWithUnits(name: string, recipeId: number, materialTypeId: number, mixMaterials: { materialId: number, quantity: number, percents: boolean }[], units: string): Observable { + saveWithUnits(name: string, recipeId: number, materialTypeId: number, mixMaterials: MixMaterialDto[], units: string): Observable { return this.save(name, recipeId, materialTypeId, this.convertMixMaterialsToMl(mixMaterials, units)) } - save(name: string, recipeId: number, materialTypeId: number, mixMaterials: { materialId: number, quantity: number }[]): Observable { + save(name: string, recipeId: number, materialTypeId: number, mixMaterials: MixMaterialDto[]): Observable { const body = { name, recipeId, materialTypeId, - mixMaterials: {} + mixMaterials: [] } this.appendMixMaterialsToBody(mixMaterials, body) return this.api.post('/recipe/mix', body) } - updateWithUnits(id: number, name: string, materialTypeId: number, mixMaterials: { materialId: number, quantity: number, percents: boolean }[], units: string): Observable { + updateWithUnits(id: number, name: string, materialTypeId: number, mixMaterials: MixMaterialDto[], units: string): Observable { return this.update(id, name, materialTypeId, this.convertMixMaterialsToMl(mixMaterials, units)) } - update(id: number, name: string, materialTypeId: number, mixMaterials: { materialId: number, quantity: number }[]): Observable { + update(id: number, name: string, materialTypeId: number, mixMaterials: MixMaterialDto[]): Observable { const body = { id, name, materialTypeId, - mixMaterials: {} + mixMaterials: [] } + this.appendMixMaterialsToBody(mixMaterials, body) return this.api.put('/recipe/mix', body) } @@ -55,25 +56,21 @@ export class MixService { return this.api.delete(`/recipe/mix/${id}`) } - extractMixMaterials(mix: Mix): { materialId: number, quantity: number, percents: boolean }[] { - return mix.mixMaterials.map(m => { - return {materialId: m.material.id, quantity: m.quantity, percents: m.material.materialType.usePercentages} - }) - } - - private convertMixMaterialsToMl(mixMaterials: { materialId: number, quantity: number, percents: boolean }[], units: string): { materialId: number, quantity: number }[] { + private convertMixMaterialsToMl(mixMaterials: MixMaterialDto[], units: string): MixMaterialDto[] { return mixMaterials.map(m => { - return { - materialId: m.materialId, - quantity: convertMixMaterialQuantity(m, units, UNIT_MILLILITER) - } + m.quantity = convertMixMaterialQuantity(m, units, UNIT_MILLILITER) + return m }) } - private appendMixMaterialsToBody(mixMaterials: { materialId: number, quantity: number }[], body: any) { - mixMaterials - .filter(m => m.materialId != null && m.quantity != null) - .forEach(m => body.mixMaterials[m.materialId] = m.quantity) + private appendMixMaterialsToBody(mixMaterials: MixMaterialDto[], body: any) { + mixMaterials.filter(m => m.materialId != null && m.quantity != null).forEach(m => { + body.mixMaterials.push({ + materialId: m.materialId, + quantity: m.quantity, + position: m.position + }) + }) } } diff --git a/src/app/modules/shared/model/recipe.model.ts b/src/app/modules/shared/model/recipe.model.ts index 4eff8c2..bd01c52 100644 --- a/src/app/modules/shared/model/recipe.model.ts +++ b/src/app/modules/shared/model/recipe.model.ts @@ -58,6 +58,16 @@ export class MixMaterial { } } +export class MixMaterialDto { + constructor( + public materialId: number, + public quantity: number, + public isPercents: boolean, + public position: number + ) { + } +} + class MixType { constructor( public id: number, @@ -90,3 +100,16 @@ export function sortRecipeSteps(steps: RecipeStep[]): RecipeStep[] { return steps.sort((a, b) => a.position - b.position) } +export function mixMaterialsAsMixMaterialsDto(mix: Mix): MixMaterialDto[] { + return sortMixMaterialsDto(mix.mixMaterials.map(m => new MixMaterialDto( + m.material.id, + m.quantity, + m.material.materialType.usePercentages, + m.position + ))) +} + +export function sortMixMaterialsDto(mixMaterials: MixMaterialDto[]): MixMaterialDto[] { + return mixMaterials.sort((a, b) => a.position - b.position) +} + diff --git a/src/app/modules/shared/units.ts b/src/app/modules/shared/units.ts index 8ee70e5..403f136 100644 --- a/src/app/modules/shared/units.ts +++ b/src/app/modules/shared/units.ts @@ -1,3 +1,5 @@ +import {MixMaterialDto} from './model/recipe.model' + export const UNIT_MILLILITER = 'mL' export const UNIT_LITER = 'L' export const UNIT_GALLON = 'gal' @@ -23,8 +25,8 @@ export const UNIT_RATIOS = { } } -export function convertMixMaterialQuantity(computedQuantity: { percents: boolean, quantity: number }, from: string, to: string): number { - return !computedQuantity.percents ? convertQuantity(computedQuantity.quantity, from, to) : computedQuantity.quantity +export function convertMixMaterialQuantity(computedQuantity: MixMaterialDto, from: string, to: string): number { + return !computedQuantity.isPercents ? convertQuantity(computedQuantity.quantity, from, to) : computedQuantity.quantity } export function convertQuantity(quantity: number, from: string, to: string): number { From 07d8333dc99bcefc528fd3c5270f8cf7be1c7fd7 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Mon, 29 Mar 2021 20:26:18 -0400 Subject: [PATCH 4/4] Correction de plusieurs bugs. --- .../mix-editor/mix-editor.component.html | 12 +++++++++--- .../mix-editor/mix-editor.component.ts | 15 +++++++++++++-- .../components/mix-table/mix-table.component.ts | 11 ++++++++--- .../step-list/step-list.component.html | 2 +- .../colors/pages/edit/edit.component.html | 4 +++- .../modules/colors/pages/edit/edit.component.ts | 6 +++--- .../colors/pages/explore/explore.component.ts | 4 ++-- src/app/modules/shared/model/recipe.model.ts | 16 ++++++++-------- 8 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/app/modules/colors/components/mix-editor/mix-editor.component.html b/src/app/modules/colors/components/mix-editor/mix-editor.component.html index 1c1ca94..7a356dc 100644 --- a/src/app/modules/colors/components/mix-editor/mix-editor.component.html +++ b/src/app/modules/colors/components/mix-editor/mix-editor.component.html @@ -71,9 +71,15 @@ diff --git a/src/app/modules/colors/components/mix-editor/mix-editor.component.ts b/src/app/modules/colors/components/mix-editor/mix-editor.component.ts index 0aa425f..fec8b0d 100644 --- a/src/app/modules/colors/components/mix-editor/mix-editor.component.ts +++ b/src/app/modules/colors/components/mix-editor/mix-editor.component.ts @@ -108,6 +108,12 @@ export class MixEditorComponent extends ErrorHandlingComponent { removeRow(position: number) { this.mixMaterials.splice(position, 1) + + // Decreases the position of each mix material above the removed one + for (let i = position; i < this.mixMaterials.length; i++) { + this.mixMaterials[i].position -= 1 + } + this.mixTable.renderRows() } @@ -126,6 +132,11 @@ export class MixEditorComponent extends ErrorHandlingComponent { table.renderRows() } + setMixMaterialMaterial(mixMaterial: MixMaterialDto, materialId: number) { + mixMaterial.isPercents = this.materials.find(m => m.id === materialId).materialType.usePercentages + mixMaterial.materialId = materialId + } + submit() { this.save.emit({ name: this.nameControl.value, @@ -141,8 +152,8 @@ export class MixEditorComponent extends ErrorHandlingComponent { this.subscribeAndNavigate(this.mixService.delete(this.mixId), `/color/edit/${this.recipeId}`) } - getAvailableMaterials(selector: MatSelect): Material[] { - return this.materials.filter(m => selector.value === m.id || this.mixMaterials.filter(mm => mm.materialId === m.id).length === 0) + getAvailableMaterials(mixMaterial: MixMaterialDto): Material[] { + return this.materials.filter(m => mixMaterial.materialId === m.id || this.mixMaterials.filter(mm => mm.materialId === m.id).length === 0) } get canDeleteMix() { diff --git a/src/app/modules/colors/components/mix-table/mix-table.component.ts b/src/app/modules/colors/components/mix-table/mix-table.component.ts index 8a31b9f..61240c3 100644 --- a/src/app/modules/colors/components/mix-table/mix-table.component.ts +++ b/src/app/modules/colors/components/mix-table/mix-table.component.ts @@ -76,11 +76,16 @@ export class MixTableComponent extends SubscribingComponent { this.locationChange.emit({id: this.mix.id, location: event.target.value}) } - changeQuantity(event: any, mixMaterial: MixMaterial, isTotal = false) { + changeQuantity(event: any, mixMaterial: MixMaterialDto, isTotal = false) { const newQuantity = parseInt(event.target.value) + // Skip if there if the input is null + if (!newQuantity) { + return + } + let ratio = 1 if (!isTotal) { - const originalQuantity = this.findMixMaterialDto(mixMaterial.material.id) + const originalQuantity = this.findMixMaterialDto(mixMaterial.materialId) ratio = newQuantity / originalQuantity.quantity } else { ratio = newQuantity / this.getTotalQuantity() @@ -98,7 +103,7 @@ export class MixTableComponent extends SubscribingComponent { } getMixMaterialQuantityRounded(mixMaterial: MixMaterialDto): number { - return this.round(this.getMixMaterialFromDto(this.findMixMaterialDto(mixMaterial.materialId)).quantity) + return this.round(this.findMixMaterialDto(mixMaterial.materialId).quantity) } getTotalQuantity(index: number = -1): number { diff --git a/src/app/modules/colors/components/step-list/step-list.component.html b/src/app/modules/colors/components/step-list/step-list.component.html index f514e70..efb9c0c 100644 --- a/src/app/modules/colors/components/step-list/step-list.component.html +++ b/src/app/modules/colors/components/step-list/step-list.component.html @@ -10,6 +10,6 @@

Aucun groupe n'est sélectionné

-

Il n'y a aucune étape définie pour ce groupe

+

Il n'y a aucune étape définie pour ce groupe

diff --git a/src/app/modules/colors/pages/edit/edit.component.html b/src/app/modules/colors/pages/edit/edit.component.html index 2ff1d65..8ec157a 100644 --- a/src/app/modules/colors/pages/edit/edit.component.html +++ b/src/app/modules/colors/pages/edit/edit.component.html @@ -6,7 +6,7 @@ - + Unités @@ -51,3 +51,5 @@ + + diff --git a/src/app/modules/colors/pages/edit/edit.component.ts b/src/app/modules/colors/pages/edit/edit.component.ts index 6b3acc6..b801f16 100644 --- a/src/app/modules/colors/pages/edit/edit.component.ts +++ b/src/app/modules/colors/pages/edit/edit.component.ts @@ -1,6 +1,6 @@ import {Component, ViewChild} from '@angular/core' import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' -import {Recipe, RecipeStep} from '../../../shared/model/recipe.model' +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' @@ -131,10 +131,10 @@ export class EditComponent extends ErrorHandlingComponent { parseInt(this.activatedRoute.snapshot.paramMap.get('id')), recipe => { this.recipe = recipe - if (this.recipe.mixCount == 0) { + if (recipeMixCount(this.recipe) == 0) { this.alertService.pushWarning('Il n\'y a aucun mélange dans cette recette') } - if (this.recipe.stepCount == 0) { + if (recipeStepCount(this.recipe) == 0) { this.alertService.pushWarning('Il n\'y a aucune étape dans cette recette') } }, diff --git a/src/app/modules/colors/pages/explore/explore.component.ts b/src/app/modules/colors/pages/explore/explore.component.ts index a83add8..3dc9b6e 100644 --- a/src/app/modules/colors/pages/explore/explore.component.ts +++ b/src/app/modules/colors/pages/explore/explore.component.ts @@ -2,7 +2,7 @@ import {Component} from '@angular/core' import {RecipeService} from '../../services/recipe.service' import {ActivatedRoute, Router} from '@angular/router' import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' -import {MixMaterialDto, Recipe, recipeNoteForGroupId} from '../../../shared/model/recipe.model' +import {MixMaterialDto, Recipe, recipeMixCount, recipeNoteForGroupId, recipeStepCount} from '../../../shared/model/recipe.model' import {Observable, Subject} from 'rxjs' import {ErrorModel, ErrorService} from '../../../shared/service/error.service' import {AlertService} from '../../../shared/service/alert.service' @@ -62,7 +62,7 @@ export class ExploreComponent extends ErrorHandlingComponent { r => { this.recipe = r - if (this.recipe.mixCount <= 0 || this.recipe.stepCount <= 0) { + if (recipeMixCount(this.recipe) <= 0 || recipeStepCount(this.recipe) <= 0) { this.alertService.pushWarning('Cette recette n\'est pas complète') } }, diff --git a/src/app/modules/shared/model/recipe.model.ts b/src/app/modules/shared/model/recipe.model.ts index bd01c52..3355946 100644 --- a/src/app/modules/shared/model/recipe.model.ts +++ b/src/app/modules/shared/model/recipe.model.ts @@ -18,14 +18,6 @@ export class Recipe { public groupsInformation: RecipeGroupInformation[] ) { } - - get mixCount(): number { - return this.mixes.length - } - - get stepCount(): number { - return this.groupsInformation.flatMap(i => i.steps).length - } } export class RecipeGroupInformation { @@ -86,6 +78,14 @@ export class RecipeStep { } } +export function recipeMixCount(recipe: Recipe): number { + return recipe.mixes.length +} + +export function recipeStepCount(recipe: Recipe): number { + return recipe.groupsInformation.length > 0 ? recipe.groupsInformation.flatMap(i => i.steps).length : 0 +} + export function recipeNoteForGroupId(recipe: Recipe, groupId: number): string | null { const groupInformation = recipe.groupsInformation.find(i => i.group.id === groupId) return groupInformation ? groupInformation.note : null
Position{{mixMaterial.position}}Produit{{mixMaterial.material.name}}{{getMixMaterialFromDto(mixMaterial).material.name}} Type{{mixMaterial.material.materialType.name}}{{getMixMaterialFromDto(mixMaterial).material.materialType.name}} Quantité{{getComputedQuantityRounded(mixMaterial)}}{{getMixMaterialQuantityRounded(mixMaterial)}} Calcul Unités - % - {{units}} + % + {{units}} {{units}}
Produit - - {{material.name}} + + + {{material.name}} +