From ae5dac1040ba2838c01c29b2d9ded5c32b4a3b1b Mon Sep 17 00:00:00 2001 From: William Nolin Date: Tue, 7 Sep 2021 15:53:32 -0400 Subject: [PATCH 01/28] #13 Use new API for app's logo and icon --- src/app/app.component.ts | 3 +- .../modules/configuration/config-editor.html | 32 +++++++++---------- .../modules/configuration/config-editor.ts | 4 +-- .../modules/configuration/config-image.html | 2 +- src/app/modules/configuration/config.ts | 20 +++++++++--- .../components/header/header.component.ts | 2 +- src/app/modules/shared/model/config.model.ts | 8 ++--- .../modules/shared/service/config.service.ts | 9 +++--- src/app/modules/shared/utils/utils.ts | 4 +++ 9 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7f5758f..0d6e334 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -5,7 +5,6 @@ import {SubscribingComponent} from './modules/shared/components/subscribing.comp import {ActivatedRoute, Router} from '@angular/router' import {ErrorService} from './modules/shared/service/error.service' import {ConfigService} from './modules/shared/service/config.service' -import {Config} from './modules/shared/model/config.model' import {environment} from '../environments/environment' @Component({ @@ -38,7 +37,7 @@ export class AppComponent extends SubscribingComponent { online => this.isServerOnline = online ) - this.favIcon.href = environment.apiUrl + "/file?path=images%2Ficon" + this.favIcon.href = environment.apiUrl + "/config/icon" } reload() { diff --git a/src/app/modules/configuration/config-editor.html b/src/app/modules/configuration/config-editor.html index d9fa87b..c8af260 100644 --- a/src/app/modules/configuration/config-editor.html +++ b/src/app/modules/configuration/config-editor.html @@ -11,23 +11,23 @@
- - - - - - - - + + - - - - - - - - + + diff --git a/src/app/modules/configuration/config-editor.ts b/src/app/modules/configuration/config-editor.ts index bde9502..b12502a 100644 --- a/src/app/modules/configuration/config-editor.ts +++ b/src/app/modules/configuration/config-editor.ts @@ -16,8 +16,8 @@ export class CreConfigEditor extends ErrorHandlingComponent { keys = { INSTANCE_NAME: Config.INSTANCE_NAME, - INSTANCE_LOGO_PATH: Config.INSTANCE_LOGO_PATH, - INSTANCE_ICON_PATH: Config.INSTANCE_ICON_PATH, + INSTANCE_LOGO_SET: Config.INSTANCE_LOGO_SET, + INSTANCE_ICON_SET: Config.INSTANCE_ICON_SET, INSTANCE_URL: Config.INSTANCE_URL, DATABASE_URL: Config.DATABASE_URL, DATABASE_USER: Config.DATABASE_USER, diff --git a/src/app/modules/configuration/config-image.html b/src/app/modules/configuration/config-image.html index 084aad1..c801323 100644 --- a/src/app/modules/configuration/config-image.html +++ b/src/app/modules/configuration/config-image.html @@ -18,7 +18,7 @@
diff --git a/src/app/modules/configuration/config.ts b/src/app/modules/configuration/config.ts index 29acafb..d40479e 100644 --- a/src/app/modules/configuration/config.ts +++ b/src/app/modules/configuration/config.ts @@ -1,10 +1,20 @@ -import {AfterViewInit, Component, ContentChild, Directive, EventEmitter, Input, Output, ViewChild, ViewEncapsulation} from '@angular/core' +import { + AfterViewInit, + Component, + ContentChild, + Directive, + EventEmitter, + Input, + Output, + ViewChild, + ViewEncapsulation +} from '@angular/core' import {ConfigService} from '../shared/service/config.service' import {Config, ConfigControl} from '../shared/model/config.model' import {SubscribingComponent} from '../shared/components/subscribing.component' import {ErrorService} from '../shared/service/error.service' import {ActivatedRoute, Router} from '@angular/router' -import {formatDate, formatDateTime, getFileUrl, readFile} from '../shared/utils/utils' +import {formatDate, formatDateTime, getConfiguredImageUrl, getFileUrl, readFile} from '../shared/utils/utils' import {AbstractControl} from '@angular/forms' import {CrePromptDialog} from '../shared/components/dialogs/dialogs' @@ -121,9 +131,9 @@ export class CreImageConfig extends _CreConfigBase { readFile(file, (content) => this.updatedImage = content) } - - get configuredImageUrl(): string { - return getFileUrl(this.config.content) + get imageUrl(): string { + const path = this.config.key == Config.INSTANCE_ICON_SET ? 'icon' : 'logo' + return getConfiguredImageUrl(path) } } diff --git a/src/app/modules/shared/components/header/header.component.ts b/src/app/modules/shared/components/header/header.component.ts index 94f4563..6d113fd 100644 --- a/src/app/modules/shared/components/header/header.component.ts +++ b/src/app/modules/shared/components/header/header.component.ts @@ -66,7 +66,7 @@ export class HeaderComponent extends SubscribingComponent { } get logoUrl(): string { - return environment.apiUrl + "/file?path=images%2Flogo&mediaType=image/png" + return environment.apiUrl + "/config/logo" } set activeLink(link: string) { diff --git a/src/app/modules/shared/model/config.model.ts b/src/app/modules/shared/model/config.model.ts index 02e4923..70011e1 100644 --- a/src/app/modules/shared/model/config.model.ts +++ b/src/app/modules/shared/model/config.model.ts @@ -3,8 +3,8 @@ import {filterMap} from '../utils/map.utils' export class Config { static readonly INSTANCE_NAME = 'instance.name' - static readonly INSTANCE_LOGO_PATH = 'instance.logo.path' - static readonly INSTANCE_ICON_PATH = 'instance.icon.path' + static readonly INSTANCE_LOGO_SET = 'instance.logo.set' + static readonly INSTANCE_ICON_SET = 'instance.icon.set' static readonly INSTANCE_URL = 'instance.url' static readonly DATABASE_URL = 'database.url' static readonly DATABASE_USER = 'database.user' @@ -20,8 +20,8 @@ export class Config { static readonly OPERATING_SYSTEM = 'env.os' static readonly IMAGE_CONFIG_KEYS = [ - Config.INSTANCE_LOGO_PATH, - Config.INSTANCE_ICON_PATH + Config.INSTANCE_LOGO_SET, + Config.INSTANCE_ICON_SET ] static readonly PASSWORD_CONFIG_KEYS = [ diff --git a/src/app/modules/shared/service/config.service.ts b/src/app/modules/shared/service/config.service.ts index dcfd95d..546ce89 100644 --- a/src/app/modules/shared/service/config.service.ts +++ b/src/app/modules/shared/service/config.service.ts @@ -39,11 +39,12 @@ export class ConfigService { } setImage(key: string, image: File): Observable { - const body = new FormData() - body.append('key', key) - body.append('image', image) + const path = key == Config.INSTANCE_ICON_SET ? 'icon' : 'logo'; - return this.api.put('/config/image', body) + const body = new FormData() + body.append(path, image) + + return this.api.put(`/config/${path}`, body) } restart(): Observable { diff --git a/src/app/modules/shared/utils/utils.ts b/src/app/modules/shared/utils/utils.ts index bd54ea9..316a49c 100644 --- a/src/app/modules/shared/utils/utils.ts +++ b/src/app/modules/shared/utils/utils.ts @@ -60,3 +60,7 @@ export function readFile(file: File, consumer: (any) => void) { export function getFileUrl(path: string) { return `${environment.apiUrl}/file?path=${encodeURIComponent(path)}` } + +export function getConfiguredImageUrl(path: string) { + return `${environment.apiUrl}/config/${path}` +} From 951f9fcb87f01536c407ad2667e50678951481ad Mon Sep 17 00:00:00 2001 From: William Nolin Date: Fri, 10 Sep 2021 07:40:38 -0400 Subject: [PATCH 02/28] #14 Add message in the color list --- .../colors/pages/list/list.component.html | 15 +- .../colors/pages/list/list.component.ts | 51 +++++-- .../modules/colors/services/recipe.service.ts | 131 +++++++++--------- 3 files changed, 112 insertions(+), 85 deletions(-) diff --git a/src/app/modules/colors/pages/list/list.component.html b/src/app/modules/colors/pages/list/list.component.html index 84493bf..7b938d7 100644 --- a/src/app/modules/colors/pages/list/list.component.html +++ b/src/app/modules/colors/pages/list/list.component.html @@ -5,7 +5,7 @@ matInput type="text" [(ngModel)]="searchQuery" - (keyup)="searchRecipes()"/> + (keyup)="searchRecipes()"/>
+
+

Il n'y a actuellement aucune recette enregistrée dans le système.

+

Vous pouvez en créer une ici.

+
+ - {{companyRecipes.company}} + {{company.name}} - + = new Map() tableCols = ['name', 'description', 'color', 'sample', 'iconNotApproved', 'buttonView', 'buttonEdit'] searchQuery = '' panelForcedExpanded = false hiddenRecipes = [] constructor( + private companyService: CompanyService, private recipeService: RecipeService, private accountService: AccountService, private configService: ConfigService, @@ -37,21 +41,35 @@ export class ListComponent extends ErrorHandlingComponent { ngOnInit() { super.ngOnInit() - this.appState.title = "Explorateur" + this.appState.title = 'Explorateur' + // Navigate to configs if server is in emergency mode this.subscribe( this.configService.get(Config.EMERGENCY_MODE), config => { - if (config.content === "false") { - this.subscribe( - this.recipeService.allSortedByCompany, - recipes => this.recipes = recipes - ) - } else { - this.urlUtils.navigateTo("/admin/config") + if (config.content == "true") { + this.urlUtils.navigateTo('/admin/config/') } } ) + + this.fetchCompanies() + // this.fetchRecipes() + } + + private fetchCompanies() { + this.subscribe( + this.companyService.all, + companies => this.companies = companies + ) + } + + private fetchRecipes() { + this.subscribe( + this.recipeService.allByCompany, + recipes => this.recipes = recipes, + true + ) } searchRecipes() { @@ -60,13 +78,16 @@ export class ListComponent extends ErrorHandlingComponent { this.cdRef.detectChanges() } - this.recipes - .flatMap(r => r.recipes) - .forEach(r => this.recipeMatchesSearchQuery(r)) + for (let recipeArray of this.recipes.values()) { + recipeArray.forEach(recipe => this.recipeMatchesSearchQuery(recipe)) + } } - isCompanyHidden(companyRecipes: Recipe[]): boolean { - return (this.searchQuery && this.searchQuery.length > 0) && companyRecipes.map(r => this.hiddenRecipes[r.id]).filter(r => !r).length <= 0 + isCompanyHidden(company: Company): boolean { + const companyRecipes = this.recipes.get(company.id); + return !(companyRecipes && companyRecipes.length >= 0) || + this.searchQuery && this.searchQuery.length > 0 && + companyRecipes.map(r => this.hiddenRecipes[r.id]).filter(r => !r).length <= 0 } isLight(recipe: Recipe): boolean { diff --git a/src/app/modules/colors/services/recipe.service.ts b/src/app/modules/colors/services/recipe.service.ts index 1cda0ce..d110d1a 100644 --- a/src/app/modules/colors/services/recipe.service.ts +++ b/src/app/modules/colors/services/recipe.service.ts @@ -3,86 +3,87 @@ 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 {Company} from '../../shared/model/company.model'; @Injectable({ - providedIn: 'root' + providedIn: 'root' }) export class RecipeService { - constructor( - private api: ApiService - ) { - } + constructor( + private api: ApiService + ) { + } - get all(): Observable { - return this.api.get('/recipe') - } + get all(): Observable { + return this.api.get('/recipe') + } - getAllByName(name: string): Observable { - return this.api.get(`/recipe?name=${name}`) - } + getAllByName(name: string): Observable { + return this.api.get(`/recipe?name=${name}`) + } - get allSortedByCompany(): Observable<{ company: string, recipes: Recipe[] }[]> { - return this.all.pipe(map(recipes => { - const mapped = [] - recipes.forEach(r => { - if (!mapped[r.company.id]) { - mapped[r.company.id] = {company: r.company.name, recipes: []} + get allByCompany(): Observable> { + return this.all.pipe(map(recipes => { + const map = new Map() + recipes.forEach(r => { + if (!map.has(r.company.id)) { + map.set(r.company.id, []) + } + map.get(r.company.id).push(r) + }) + return map + })) + } + + getById(id: number): Observable { + return this.api.get(`/recipe/${id}`) + } + + save(name: string, description: string, color: string, gloss: number, sample: number, approbationDate: string, remark: string, companyId: number): Observable { + const body = {name, description, color, gloss, sample, remark, companyId} + if (approbationDate) { + // @ts-ignore + body.approbationDate = approbationDate } - mapped[r.company.id].recipes.push(r) - }) - return mapped.filter(e => e != null) // Filter to remove empty elements in the array that appears for some reason - })) - } - - getById(id: number): Observable { - return this.api.get(`/recipe/${id}`) - } - - save(name: string, description: string, color: string, gloss: number, sample: number, approbationDate: string, remark: string, companyId: number): Observable { - const body = {name, description, color, gloss, sample, remark, companyId} - if (approbationDate) { - // @ts-ignore - body.approbationDate = approbationDate - } - return this.api.post('/recipe', body) - } - - 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 + return this.api.post('/recipe', body) } - steps.forEach((groupSteps, groupId) => { - const mappedGroupSteps = groupSteps.map(s => { - return {message: s.message, position: s.position} - }) - body.steps.push({groupId, steps: mappedGroupSteps}) - }) + 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 + } - return this.api.put('/recipe', body) - } + steps.forEach((groupSteps, groupId) => { + const mappedGroupSteps = groupSteps.map(s => { + return {message: s.message, position: s.position} + }) + body.steps.push({groupId, steps: mappedGroupSteps}) + }) - updateExplorerModifications(id: number, notes: Map, mixesLocationChange: Map): Observable { - const body = { - recipeId: id, - notes: [], - mixesLocation: [] + return this.api.put('/recipe', body) } - notes.forEach((content, groupId) => { - body.notes.push({groupId, content}) - }) + updateExplorerModifications(id: number, notes: Map, mixesLocationChange: Map): Observable { + const body = { + recipeId: id, + notes: [], + mixesLocation: [] + } - mixesLocationChange.forEach((location, mixId) => { - body.mixesLocation.push({mixId, location}) - }) + notes.forEach((content, groupId) => { + body.notes.push({groupId, content}) + }) - return this.api.put('/recipe/public', body) - } + mixesLocationChange.forEach((location, mixId) => { + body.mixesLocation.push({mixId, location}) + }) - delete(id: number): Observable { - return this.api.delete(`/recipe/${id}`) - } + return this.api.put('/recipe/public', body) + } + + delete(id: number): Observable { + return this.api.delete(`/recipe/${id}`) + } } From 73bb2c3bce83d9d87413c28c8fd3b21b97038898 Mon Sep 17 00:00:00 2001 From: William Nolin Date: Fri, 10 Sep 2021 07:55:24 -0400 Subject: [PATCH 03/28] #14 Add messages in the color list --- .../modules/colors/pages/list/list.component.html | 12 +++++++++--- .../modules/colors/pages/list/list.component.ts | 8 ++++++-- .../modules/shared/components/alerts/alerts.html | 3 +++ .../shared/components/alerts/alerts.module.ts | 14 ++++++++++++++ src/app/modules/shared/components/alerts/alerts.ts | 9 +++++++++ .../shared/components/subscribing.component.ts | 4 ++++ src/app/modules/shared/shared.module.ts | 4 +++- 7 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 src/app/modules/shared/components/alerts/alerts.html create mode 100644 src/app/modules/shared/components/alerts/alerts.module.ts create mode 100644 src/app/modules/shared/components/alerts/alerts.ts diff --git a/src/app/modules/colors/pages/list/list.component.html b/src/app/modules/colors/pages/list/list.component.html index 7b938d7..d06df5d 100644 --- a/src/app/modules/colors/pages/list/list.component.html +++ b/src/app/modules/colors/pages/list/list.component.html @@ -20,9 +20,15 @@
-
-

Il n'y a actuellement aucune recette enregistrée dans le système.

-

Vous pouvez en créer une ici.

+
+ +

Il n'y a actuellement aucune bannière enregistrée dans le système.

+

Vous pouvez en créer une ici.

+
+ +

Il n'y a actuellement aucune recette enregistrée dans le système.

+

Vous pouvez en créer une ici.

+
+ +
diff --git a/src/app/modules/shared/components/alerts/alerts.module.ts b/src/app/modules/shared/components/alerts/alerts.module.ts new file mode 100644 index 0000000..110fde4 --- /dev/null +++ b/src/app/modules/shared/components/alerts/alerts.module.ts @@ -0,0 +1,14 @@ +import {NgModule} from '@angular/core'; +import {WarningAlert} from './alerts'; + +@NgModule({ + declarations: [ + WarningAlert + ], + exports: [ + WarningAlert + ], + imports: [] +}) +export class CreAlertsModule { +} diff --git a/src/app/modules/shared/components/alerts/alerts.ts b/src/app/modules/shared/components/alerts/alerts.ts new file mode 100644 index 0000000..e150819 --- /dev/null +++ b/src/app/modules/shared/components/alerts/alerts.ts @@ -0,0 +1,9 @@ +import {Component} from '@angular/core'; + +@Component({ + selector: 'cre-warning-alert', + templateUrl: 'alerts.html' +}) +export class WarningAlert { + +} diff --git a/src/app/modules/shared/components/subscribing.component.ts b/src/app/modules/shared/components/subscribing.component.ts index a31dcd4..d003d0a 100644 --- a/src/app/modules/shared/components/subscribing.component.ts +++ b/src/app/modules/shared/components/subscribing.component.ts @@ -11,6 +11,8 @@ export abstract class SubscribingComponent implements OnInit, OnDestroy { protected subscribers$ = [] protected destroy$ = new Subject() + loading = false + protected constructor( protected errorService: ErrorService, protected activatedRoute: ActivatedRoute, @@ -74,12 +76,14 @@ export abstract class SubscribingComponent implements OnInit, OnDestroy { protected showLoadingWheel(shouldShowWheel) { if (shouldShowWheel) { + this.loading = true globalLoadingWheel.show() } } protected hideLoadingWheel(shouldShowWheel) { if (shouldShowWheel) { + this.loading = false globalLoadingWheel.hide() } } diff --git a/src/app/modules/shared/shared.module.ts b/src/app/modules/shared/shared.module.ts index 05aaf24..d30b0b4 100644 --- a/src/app/modules/shared/shared.module.ts +++ b/src/app/modules/shared/shared.module.ts @@ -37,6 +37,7 @@ import {CreFormsModule} from './components/forms/forms.module' import {VarDirective} from './directives/var.directive' import {CreColorPreview} from './components/color-preview/color-preview' import {CreDialogsModule} from './components/dialogs/dialogs.module' +import {CreAlertsModule} from './components/alerts/alerts.module'; @NgModule({ declarations: [VarDirective, HeaderComponent, UserMenuComponent, LabeledIconComponent, ConfirmBoxComponent, PermissionsListComponent, PermissionsFieldComponent, NavComponent, EntityListComponent, EntityAddComponent, EntityEditComponent, FileButtonComponent, GlobalAlertHandlerComponent, SliderFieldComponent, LoadingWheelComponent, CreColorPreview], @@ -73,7 +74,8 @@ import {CreDialogsModule} from './components/dialogs/dialogs.module' CreFormsModule, VarDirective, CreColorPreview, - CreDialogsModule + CreDialogsModule, + CreAlertsModule ], imports: [ MatTabsModule, From c35635c596b9b260ca8238d3fc49229a482897f5 Mon Sep 17 00:00:00 2001 From: William Nolin Date: Tue, 14 Sep 2021 09:28:28 -0400 Subject: [PATCH 04/28] #14 Add messages when adding recipe --- src/app/app-routing.module.ts | 2 +- .../colors/pages/add/add.component.html | 6 - .../colors/pages/add/add.component.sass | 0 .../modules/colors/pages/add/add.component.ts | 123 ------------------ .../modules/colors/services/recipe.service.ts | 89 ------------- .../company/service/company.service.ts | 6 +- src/app/modules/material/material.module.ts | 4 +- src/app/modules/recipes/add.html | 1 + src/app/modules/{colors => recipes}/bpac.js | 0 .../images-editor.component.html | 0 .../images-editor.component.sass | 0 .../images-editor/images-editor.component.ts | 0 .../mix-editor/mix-editor.component.html | 0 .../mix-editor/mix-editor.component.sass | 0 .../mix-editor/mix-editor.component.ts | 0 .../mix-table/mix-table.component.html | 0 .../mix-table/mix-table.component.sass | 0 .../mix-table/mix-table.component.ts | 0 .../mixes-card/mixes-card.component.html | 0 .../mixes-card/mixes-card.component.sass | 0 .../mixes-card/mixes-card.component.ts | 0 .../recipe-info/recipe-info.component.html | 0 .../recipe-info/recipe-info.component.sass | 0 .../recipe-info/recipe-info.component.ts | 0 .../step-list/step-list.component.html | 0 .../step-list/step-list.component.sass | 0 .../step-list/step-list.component.ts | 0 .../step-table/step-table.component.html | 0 .../step-table/step-table.component.sass | 0 .../step-table/step-table.component.ts | 0 .../unit-selector.component.html | 0 .../unit-selector.component.sass | 0 .../unit-selector/unit-selector.component.ts | 0 src/app/modules/recipes/form.html | 24 ++++ .../pages/edit/edit.component.html | 0 .../pages/edit/edit.component.sass | 0 .../pages/edit/edit.component.ts | 0 .../pages/explore/explore.component.html | 0 .../pages/explore/explore.component.sass | 0 .../pages/explore/explore.component.ts | 0 .../pages/list/list.component.html | 0 .../pages/list/list.component.sass | 0 .../pages/list/list.component.ts | 2 +- .../pages/mix/mix-add/mix-add.component.html | 0 .../pages/mix/mix-add/mix-add.component.sass | 0 .../pages/mix/mix-add/mix-add.component.ts | 0 .../mix/mix-edit/mix-edit.component.html | 0 .../mix/mix-edit/mix-edit.component.sass | 0 .../pages/mix/mix-edit/mix-edit.component.ts | 0 .../{colors => recipes}/ptouchPrint.js | 0 .../recipes-routing.module.ts} | 6 +- .../recipes.module.ts} | 32 ++++- src/app/modules/recipes/recipes.ts | 119 +++++++++++++++++ .../services/mix.service.ts | 0 .../services/recipe-image.service.ts | 0 .../recipes/services/recipe.service.ts | 89 +++++++++++++ .../shared/components/alerts/alerts.ts | 5 +- .../shared/components/forms/forms.sass | 4 + .../modules/shared/components/forms/forms.ts | 2 +- .../components/inputs/autocomplete.html | 2 +- .../components/inputs/chips-combo-box.html | 2 +- .../shared/components/inputs/combo-box.html | 13 +- .../shared/components/inputs/input.html | 2 + .../shared/components/inputs/inputs.module.ts | 10 +- .../shared/components/inputs/inputs.ts | 107 +++++++++++++-- .../shared/components/inputs/slider.html | 13 ++ src/app/modules/shared/model/recipe.model.ts | 30 ++--- .../modules/touch-up-kit/components/finish.ts | 2 +- .../modules/touch-up-kit/components/form.html | 4 +- .../modules/touch-up-kit/components/form.ts | 2 +- .../modules/touch-up-kit/pages/touchupkit.ts | 2 +- 71 files changed, 419 insertions(+), 284 deletions(-) delete mode 100644 src/app/modules/colors/pages/add/add.component.html delete mode 100644 src/app/modules/colors/pages/add/add.component.sass delete mode 100644 src/app/modules/colors/pages/add/add.component.ts delete mode 100644 src/app/modules/colors/services/recipe.service.ts create mode 100644 src/app/modules/recipes/add.html rename src/app/modules/{colors => recipes}/bpac.js (100%) rename src/app/modules/{colors => recipes}/components/images-editor/images-editor.component.html (100%) rename src/app/modules/{colors => recipes}/components/images-editor/images-editor.component.sass (100%) rename src/app/modules/{colors => recipes}/components/images-editor/images-editor.component.ts (100%) rename src/app/modules/{colors => recipes}/components/mix-editor/mix-editor.component.html (100%) rename src/app/modules/{colors => recipes}/components/mix-editor/mix-editor.component.sass (100%) rename src/app/modules/{colors => recipes}/components/mix-editor/mix-editor.component.ts (100%) rename src/app/modules/{colors => recipes}/components/mix-table/mix-table.component.html (100%) rename src/app/modules/{colors => recipes}/components/mix-table/mix-table.component.sass (100%) rename src/app/modules/{colors => recipes}/components/mix-table/mix-table.component.ts (100%) rename src/app/modules/{colors => recipes}/components/mixes-card/mixes-card.component.html (100%) rename src/app/modules/{colors => recipes}/components/mixes-card/mixes-card.component.sass (100%) rename src/app/modules/{colors => recipes}/components/mixes-card/mixes-card.component.ts (100%) rename src/app/modules/{colors => recipes}/components/recipe-info/recipe-info.component.html (100%) rename src/app/modules/{colors => recipes}/components/recipe-info/recipe-info.component.sass (100%) rename src/app/modules/{colors => recipes}/components/recipe-info/recipe-info.component.ts (100%) rename src/app/modules/{colors => recipes}/components/step-list/step-list.component.html (100%) rename src/app/modules/{colors => recipes}/components/step-list/step-list.component.sass (100%) rename src/app/modules/{colors => recipes}/components/step-list/step-list.component.ts (100%) rename src/app/modules/{colors => recipes}/components/step-table/step-table.component.html (100%) rename src/app/modules/{colors => recipes}/components/step-table/step-table.component.sass (100%) rename src/app/modules/{colors => recipes}/components/step-table/step-table.component.ts (100%) rename src/app/modules/{colors => recipes}/components/unit-selector/unit-selector.component.html (100%) rename src/app/modules/{colors => recipes}/components/unit-selector/unit-selector.component.sass (100%) rename src/app/modules/{colors => recipes}/components/unit-selector/unit-selector.component.ts (100%) create mode 100644 src/app/modules/recipes/form.html rename src/app/modules/{colors => recipes}/pages/edit/edit.component.html (100%) rename src/app/modules/{colors => recipes}/pages/edit/edit.component.sass (100%) rename src/app/modules/{colors => recipes}/pages/edit/edit.component.ts (100%) rename src/app/modules/{colors => recipes}/pages/explore/explore.component.html (100%) rename src/app/modules/{colors => recipes}/pages/explore/explore.component.sass (100%) rename src/app/modules/{colors => recipes}/pages/explore/explore.component.ts (100%) rename src/app/modules/{colors => recipes}/pages/list/list.component.html (100%) rename src/app/modules/{colors => recipes}/pages/list/list.component.sass (100%) rename src/app/modules/{colors => recipes}/pages/list/list.component.ts (99%) rename src/app/modules/{colors => recipes}/pages/mix/mix-add/mix-add.component.html (100%) rename src/app/modules/{colors => recipes}/pages/mix/mix-add/mix-add.component.sass (100%) rename src/app/modules/{colors => recipes}/pages/mix/mix-add/mix-add.component.ts (100%) rename src/app/modules/{colors => recipes}/pages/mix/mix-edit/mix-edit.component.html (100%) rename src/app/modules/{colors => recipes}/pages/mix/mix-edit/mix-edit.component.sass (100%) rename src/app/modules/{colors => recipes}/pages/mix/mix-edit/mix-edit.component.ts (100%) rename src/app/modules/{colors => recipes}/ptouchPrint.js (100%) rename src/app/modules/{colors/colors-routing.module.ts => recipes/recipes-routing.module.ts} (88%) rename src/app/modules/{colors/colors.module.ts => recipes/recipes.module.ts} (65%) create mode 100644 src/app/modules/recipes/recipes.ts rename src/app/modules/{colors => recipes}/services/mix.service.ts (100%) rename src/app/modules/{colors => recipes}/services/recipe-image.service.ts (100%) create mode 100644 src/app/modules/recipes/services/recipe.service.ts create mode 100644 src/app/modules/shared/components/inputs/slider.html diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index a0ef43d..3d9f34f 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -7,7 +7,7 @@ import {CreConfigEditor} from './modules/configuration/config-editor' const routes: Routes = [{ path: 'color', - loadChildren: () => import('./modules/colors/colors.module').then(m => m.ColorsModule) + loadChildren: () => import('./modules/recipes/recipes.module').then(m => m.RecipesModule) }, { path: 'account', loadChildren: () => import('./modules/accounts/accounts.module').then(m => m.AccountsModule) diff --git a/src/app/modules/colors/pages/add/add.component.html b/src/app/modules/colors/pages/add/add.component.html deleted file mode 100644 index f95fa2b..0000000 --- a/src/app/modules/colors/pages/add/add.component.html +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/src/app/modules/colors/pages/add/add.component.sass b/src/app/modules/colors/pages/add/add.component.sass deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/modules/colors/pages/add/add.component.ts b/src/app/modules/colors/pages/add/add.component.ts deleted file mode 100644 index e5bcf7e..0000000 --- a/src/app/modules/colors/pages/add/add.component.ts +++ /dev/null @@ -1,123 +0,0 @@ -import {Component} from '@angular/core' -import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' -import {RecipeService} from '../../services/recipe.service' -import {FormField} from '../../../shared/components/entity-add/entity-add.component' -import {Validators} from '@angular/forms' -import {CompanyService} from '../../../company/service/company.service' -import {map} from 'rxjs/operators' -import {ActivatedRoute, Router} from '@angular/router' -import {ErrorService} from '../../../shared/service/error.service' -import {AppState} from '../../../shared/app-state' - -@Component({ - selector: 'cre-add', - templateUrl: './add.component.html', - styleUrls: ['./add.component.sass'] -}) -export class AddComponent extends ErrorHandlingComponent { - formFields: FormField[] = [ - { - 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', - defaultValue: "#ffffff", - required: true, - errorMessages: [ - {conditionFn: errors => errors.required, message: 'Une couleur est requise'} - ] - }, - { - name: 'gloss', - label: 'Lustre', - type: 'slider', - min: 0, - max: 100, - defaultValue: 0, - required: true, - 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: 'select', - required: true, - errorMessages: [ - {conditionFn: errors => errors.required, message: 'Une bannière est requise'} - ], - options$: this.companyService.all.pipe(map(companies => companies.map(c => { - return {value: c.id, label: 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(values) { - this.subscribe( - this.recipeService.save(values.name, values.description, values.color, values.gloss, values.sample, values.approbationDate, values.remark, values.company), - recipe => this.urlUtils.navigateTo(`/color/edit/${recipe.id}`) - ) - } -} diff --git a/src/app/modules/colors/services/recipe.service.ts b/src/app/modules/colors/services/recipe.service.ts deleted file mode 100644 index d110d1a..0000000 --- a/src/app/modules/colors/services/recipe.service.ts +++ /dev/null @@ -1,89 +0,0 @@ -import {Injectable} from '@angular/core' -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 {Company} from '../../shared/model/company.model'; - -@Injectable({ - providedIn: 'root' -}) -export class RecipeService { - constructor( - private api: ApiService - ) { - } - - get all(): Observable { - return this.api.get('/recipe') - } - - getAllByName(name: string): Observable { - return this.api.get(`/recipe?name=${name}`) - } - - get allByCompany(): Observable> { - return this.all.pipe(map(recipes => { - const map = new Map() - recipes.forEach(r => { - if (!map.has(r.company.id)) { - map.set(r.company.id, []) - } - map.get(r.company.id).push(r) - }) - return map - })) - } - - getById(id: number): Observable { - return this.api.get(`/recipe/${id}`) - } - - save(name: string, description: string, color: string, gloss: number, sample: number, approbationDate: string, remark: string, companyId: number): Observable { - const body = {name, description, color, gloss, sample, remark, companyId} - if (approbationDate) { - // @ts-ignore - body.approbationDate = approbationDate - } - return this.api.post('/recipe', body) - } - - 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) - } - - updateExplorerModifications(id: number, notes: Map, mixesLocationChange: Map): Observable { - const body = { - recipeId: id, - notes: [], - mixesLocation: [] - } - - 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) - } - - delete(id: number): Observable { - return this.api.delete(`/recipe/${id}`) - } -} diff --git a/src/app/modules/company/service/company.service.ts b/src/app/modules/company/service/company.service.ts index 238eaef..90f3a78 100644 --- a/src/app/modules/company/service/company.service.ts +++ b/src/app/modules/company/service/company.service.ts @@ -1,7 +1,7 @@ import {Injectable} from '@angular/core'; -import {ApiService} from "../../shared/service/api.service"; -import {Observable} from "rxjs"; -import {Company} from "../../shared/model/company.model"; +import {ApiService} from '../../shared/service/api.service'; +import {Observable} from 'rxjs'; +import {Company} from '../../shared/model/company.model'; @Injectable({ providedIn: 'root' diff --git a/src/app/modules/material/material.module.ts b/src/app/modules/material/material.module.ts index 6ccb444..2b934b2 100644 --- a/src/app/modules/material/material.module.ts +++ b/src/app/modules/material/material.module.ts @@ -6,7 +6,7 @@ import {InventoryComponent} from './pages/inventory/inventory.component'; import {SharedModule} from "../shared/shared.module"; import {AddComponent} from './pages/add/add.component'; import {EditComponent} from './pages/edit/edit.component'; -import {ColorsModule} from '../colors/colors.module' +import {RecipesModule} from '../recipes/recipes.module' import {MatSortModule} from '@angular/material/sort' import {FormsModule} from '@angular/forms' @@ -17,7 +17,7 @@ import {FormsModule} from '@angular/forms' CommonModule, MaterialRoutingModule, SharedModule, - ColorsModule, + RecipesModule, MatSortModule, FormsModule ] diff --git a/src/app/modules/recipes/add.html b/src/app/modules/recipes/add.html new file mode 100644 index 0000000..185e14a --- /dev/null +++ b/src/app/modules/recipes/add.html @@ -0,0 +1 @@ + diff --git a/src/app/modules/colors/bpac.js b/src/app/modules/recipes/bpac.js similarity index 100% rename from src/app/modules/colors/bpac.js rename to src/app/modules/recipes/bpac.js diff --git a/src/app/modules/colors/components/images-editor/images-editor.component.html b/src/app/modules/recipes/components/images-editor/images-editor.component.html similarity index 100% rename from src/app/modules/colors/components/images-editor/images-editor.component.html rename to src/app/modules/recipes/components/images-editor/images-editor.component.html diff --git a/src/app/modules/colors/components/images-editor/images-editor.component.sass b/src/app/modules/recipes/components/images-editor/images-editor.component.sass similarity index 100% rename from src/app/modules/colors/components/images-editor/images-editor.component.sass rename to src/app/modules/recipes/components/images-editor/images-editor.component.sass diff --git a/src/app/modules/colors/components/images-editor/images-editor.component.ts b/src/app/modules/recipes/components/images-editor/images-editor.component.ts similarity index 100% rename from src/app/modules/colors/components/images-editor/images-editor.component.ts rename to src/app/modules/recipes/components/images-editor/images-editor.component.ts diff --git a/src/app/modules/colors/components/mix-editor/mix-editor.component.html b/src/app/modules/recipes/components/mix-editor/mix-editor.component.html similarity index 100% rename from src/app/modules/colors/components/mix-editor/mix-editor.component.html rename to src/app/modules/recipes/components/mix-editor/mix-editor.component.html diff --git a/src/app/modules/colors/components/mix-editor/mix-editor.component.sass b/src/app/modules/recipes/components/mix-editor/mix-editor.component.sass similarity index 100% rename from src/app/modules/colors/components/mix-editor/mix-editor.component.sass rename to src/app/modules/recipes/components/mix-editor/mix-editor.component.sass diff --git a/src/app/modules/colors/components/mix-editor/mix-editor.component.ts b/src/app/modules/recipes/components/mix-editor/mix-editor.component.ts similarity index 100% rename from src/app/modules/colors/components/mix-editor/mix-editor.component.ts rename to src/app/modules/recipes/components/mix-editor/mix-editor.component.ts diff --git a/src/app/modules/colors/components/mix-table/mix-table.component.html b/src/app/modules/recipes/components/mix-table/mix-table.component.html similarity index 100% rename from src/app/modules/colors/components/mix-table/mix-table.component.html rename to src/app/modules/recipes/components/mix-table/mix-table.component.html diff --git a/src/app/modules/colors/components/mix-table/mix-table.component.sass b/src/app/modules/recipes/components/mix-table/mix-table.component.sass similarity index 100% rename from src/app/modules/colors/components/mix-table/mix-table.component.sass rename to src/app/modules/recipes/components/mix-table/mix-table.component.sass diff --git a/src/app/modules/colors/components/mix-table/mix-table.component.ts b/src/app/modules/recipes/components/mix-table/mix-table.component.ts similarity index 100% rename from src/app/modules/colors/components/mix-table/mix-table.component.ts rename to src/app/modules/recipes/components/mix-table/mix-table.component.ts diff --git a/src/app/modules/colors/components/mixes-card/mixes-card.component.html b/src/app/modules/recipes/components/mixes-card/mixes-card.component.html similarity index 100% rename from src/app/modules/colors/components/mixes-card/mixes-card.component.html rename to src/app/modules/recipes/components/mixes-card/mixes-card.component.html diff --git a/src/app/modules/colors/components/mixes-card/mixes-card.component.sass b/src/app/modules/recipes/components/mixes-card/mixes-card.component.sass similarity index 100% rename from src/app/modules/colors/components/mixes-card/mixes-card.component.sass rename to src/app/modules/recipes/components/mixes-card/mixes-card.component.sass diff --git a/src/app/modules/colors/components/mixes-card/mixes-card.component.ts b/src/app/modules/recipes/components/mixes-card/mixes-card.component.ts similarity index 100% rename from src/app/modules/colors/components/mixes-card/mixes-card.component.ts rename to src/app/modules/recipes/components/mixes-card/mixes-card.component.ts diff --git a/src/app/modules/colors/components/recipe-info/recipe-info.component.html b/src/app/modules/recipes/components/recipe-info/recipe-info.component.html similarity index 100% rename from src/app/modules/colors/components/recipe-info/recipe-info.component.html rename to src/app/modules/recipes/components/recipe-info/recipe-info.component.html diff --git a/src/app/modules/colors/components/recipe-info/recipe-info.component.sass b/src/app/modules/recipes/components/recipe-info/recipe-info.component.sass similarity index 100% rename from src/app/modules/colors/components/recipe-info/recipe-info.component.sass rename to src/app/modules/recipes/components/recipe-info/recipe-info.component.sass diff --git a/src/app/modules/colors/components/recipe-info/recipe-info.component.ts b/src/app/modules/recipes/components/recipe-info/recipe-info.component.ts similarity index 100% rename from src/app/modules/colors/components/recipe-info/recipe-info.component.ts rename to src/app/modules/recipes/components/recipe-info/recipe-info.component.ts diff --git a/src/app/modules/colors/components/step-list/step-list.component.html b/src/app/modules/recipes/components/step-list/step-list.component.html similarity index 100% rename from src/app/modules/colors/components/step-list/step-list.component.html rename to src/app/modules/recipes/components/step-list/step-list.component.html diff --git a/src/app/modules/colors/components/step-list/step-list.component.sass b/src/app/modules/recipes/components/step-list/step-list.component.sass similarity index 100% rename from src/app/modules/colors/components/step-list/step-list.component.sass rename to src/app/modules/recipes/components/step-list/step-list.component.sass diff --git a/src/app/modules/colors/components/step-list/step-list.component.ts b/src/app/modules/recipes/components/step-list/step-list.component.ts similarity index 100% rename from src/app/modules/colors/components/step-list/step-list.component.ts rename to src/app/modules/recipes/components/step-list/step-list.component.ts diff --git a/src/app/modules/colors/components/step-table/step-table.component.html b/src/app/modules/recipes/components/step-table/step-table.component.html similarity index 100% rename from src/app/modules/colors/components/step-table/step-table.component.html rename to src/app/modules/recipes/components/step-table/step-table.component.html diff --git a/src/app/modules/colors/components/step-table/step-table.component.sass b/src/app/modules/recipes/components/step-table/step-table.component.sass similarity index 100% rename from src/app/modules/colors/components/step-table/step-table.component.sass rename to src/app/modules/recipes/components/step-table/step-table.component.sass diff --git a/src/app/modules/colors/components/step-table/step-table.component.ts b/src/app/modules/recipes/components/step-table/step-table.component.ts similarity index 100% rename from src/app/modules/colors/components/step-table/step-table.component.ts rename to src/app/modules/recipes/components/step-table/step-table.component.ts diff --git a/src/app/modules/colors/components/unit-selector/unit-selector.component.html b/src/app/modules/recipes/components/unit-selector/unit-selector.component.html similarity index 100% rename from src/app/modules/colors/components/unit-selector/unit-selector.component.html rename to src/app/modules/recipes/components/unit-selector/unit-selector.component.html diff --git a/src/app/modules/colors/components/unit-selector/unit-selector.component.sass b/src/app/modules/recipes/components/unit-selector/unit-selector.component.sass similarity index 100% rename from src/app/modules/colors/components/unit-selector/unit-selector.component.sass rename to src/app/modules/recipes/components/unit-selector/unit-selector.component.sass diff --git a/src/app/modules/colors/components/unit-selector/unit-selector.component.ts b/src/app/modules/recipes/components/unit-selector/unit-selector.component.ts similarity index 100% rename from src/app/modules/colors/components/unit-selector/unit-selector.component.ts rename to src/app/modules/recipes/components/unit-selector/unit-selector.component.ts diff --git a/src/app/modules/recipes/form.html b/src/app/modules/recipes/form.html new file mode 100644 index 0000000..a00dcf1 --- /dev/null +++ b/src/app/modules/recipes/form.html @@ -0,0 +1,24 @@ +
+ +

Il n'y a actuellement aucune bannière enregistrée dans le système.

+

Vous pouvez en créer une ici.

+
+
+ + + Ajouter une recette + + + + + + + + + + + + Retour + Enregistrer + + diff --git a/src/app/modules/colors/pages/edit/edit.component.html b/src/app/modules/recipes/pages/edit/edit.component.html similarity index 100% rename from src/app/modules/colors/pages/edit/edit.component.html rename to src/app/modules/recipes/pages/edit/edit.component.html diff --git a/src/app/modules/colors/pages/edit/edit.component.sass b/src/app/modules/recipes/pages/edit/edit.component.sass similarity index 100% rename from src/app/modules/colors/pages/edit/edit.component.sass rename to src/app/modules/recipes/pages/edit/edit.component.sass diff --git a/src/app/modules/colors/pages/edit/edit.component.ts b/src/app/modules/recipes/pages/edit/edit.component.ts similarity index 100% rename from src/app/modules/colors/pages/edit/edit.component.ts rename to src/app/modules/recipes/pages/edit/edit.component.ts diff --git a/src/app/modules/colors/pages/explore/explore.component.html b/src/app/modules/recipes/pages/explore/explore.component.html similarity index 100% rename from src/app/modules/colors/pages/explore/explore.component.html rename to src/app/modules/recipes/pages/explore/explore.component.html diff --git a/src/app/modules/colors/pages/explore/explore.component.sass b/src/app/modules/recipes/pages/explore/explore.component.sass similarity index 100% rename from src/app/modules/colors/pages/explore/explore.component.sass rename to src/app/modules/recipes/pages/explore/explore.component.sass diff --git a/src/app/modules/colors/pages/explore/explore.component.ts b/src/app/modules/recipes/pages/explore/explore.component.ts similarity index 100% rename from src/app/modules/colors/pages/explore/explore.component.ts rename to src/app/modules/recipes/pages/explore/explore.component.ts diff --git a/src/app/modules/colors/pages/list/list.component.html b/src/app/modules/recipes/pages/list/list.component.html similarity index 100% rename from src/app/modules/colors/pages/list/list.component.html rename to src/app/modules/recipes/pages/list/list.component.html diff --git a/src/app/modules/colors/pages/list/list.component.sass b/src/app/modules/recipes/pages/list/list.component.sass similarity index 100% rename from src/app/modules/colors/pages/list/list.component.sass rename to src/app/modules/recipes/pages/list/list.component.sass diff --git a/src/app/modules/colors/pages/list/list.component.ts b/src/app/modules/recipes/pages/list/list.component.ts similarity index 99% rename from src/app/modules/colors/pages/list/list.component.ts rename to src/app/modules/recipes/pages/list/list.component.ts index 1f82f76..53077a6 100644 --- a/src/app/modules/colors/pages/list/list.component.ts +++ b/src/app/modules/recipes/pages/list/list.component.ts @@ -53,7 +53,7 @@ export class ListComponent extends ErrorHandlingComponent { } ) - //this.fetchCompanies() + this.fetchCompanies() this.fetchRecipes() } diff --git a/src/app/modules/colors/pages/mix/mix-add/mix-add.component.html b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html similarity index 100% rename from src/app/modules/colors/pages/mix/mix-add/mix-add.component.html rename to src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html diff --git a/src/app/modules/colors/pages/mix/mix-add/mix-add.component.sass b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.sass similarity index 100% rename from src/app/modules/colors/pages/mix/mix-add/mix-add.component.sass rename to src/app/modules/recipes/pages/mix/mix-add/mix-add.component.sass diff --git a/src/app/modules/colors/pages/mix/mix-add/mix-add.component.ts b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts similarity index 100% rename from src/app/modules/colors/pages/mix/mix-add/mix-add.component.ts rename to src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts diff --git a/src/app/modules/colors/pages/mix/mix-edit/mix-edit.component.html b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html similarity index 100% rename from src/app/modules/colors/pages/mix/mix-edit/mix-edit.component.html rename to src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html diff --git a/src/app/modules/colors/pages/mix/mix-edit/mix-edit.component.sass b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.sass similarity index 100% rename from src/app/modules/colors/pages/mix/mix-edit/mix-edit.component.sass rename to src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.sass diff --git a/src/app/modules/colors/pages/mix/mix-edit/mix-edit.component.ts b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts similarity index 100% rename from src/app/modules/colors/pages/mix/mix-edit/mix-edit.component.ts rename to src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts diff --git a/src/app/modules/colors/ptouchPrint.js b/src/app/modules/recipes/ptouchPrint.js similarity index 100% rename from src/app/modules/colors/ptouchPrint.js rename to src/app/modules/recipes/ptouchPrint.js diff --git a/src/app/modules/colors/colors-routing.module.ts b/src/app/modules/recipes/recipes-routing.module.ts similarity index 88% rename from src/app/modules/colors/colors-routing.module.ts rename to src/app/modules/recipes/recipes-routing.module.ts index 879d0a1..a29258a 100644 --- a/src/app/modules/colors/colors-routing.module.ts +++ b/src/app/modules/recipes/recipes-routing.module.ts @@ -1,18 +1,18 @@ import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; import {ListComponent} from "./pages/list/list.component"; -import {AddComponent} from "./pages/add/add.component"; import {EditComponent} from "./pages/edit/edit.component"; import {ExploreComponent} from "./pages/explore/explore.component"; import {MixEditComponent} from "./pages/mix/mix-edit/mix-edit.component"; import {MixAddComponent} from "./pages/mix/mix-add/mix-add.component"; +import {RecipeAdd} from './recipes'; const routes: Routes = [{ path: 'list', component: ListComponent }, { path: 'add', - component: AddComponent + component: RecipeAdd }, { path: 'edit/:id', component: EditComponent @@ -35,5 +35,5 @@ const routes: Routes = [{ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) -export class ColorsRoutingModule { +export class RecipesRoutingModule { } diff --git a/src/app/modules/colors/colors.module.ts b/src/app/modules/recipes/recipes.module.ts similarity index 65% rename from src/app/modules/colors/colors.module.ts rename to src/app/modules/recipes/recipes.module.ts index c994650..3170cd2 100644 --- a/src/app/modules/colors/colors.module.ts +++ b/src/app/modules/recipes/recipes.module.ts @@ -1,9 +1,8 @@ import {NgModule} from '@angular/core' -import {ColorsRoutingModule} from './colors-routing.module' +import {RecipesRoutingModule} from './recipes-routing.module' import {SharedModule} from '../shared/shared.module' import {ListComponent} from './pages/list/list.component' -import {AddComponent} from './pages/add/add.component' import {EditComponent} from './pages/edit/edit.component' import {MatExpansionModule} from '@angular/material/expansion' import {FormsModule} from '@angular/forms' @@ -19,20 +18,41 @@ 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' +import {CreInputsModule} from '../shared/components/inputs/inputs.module'; +import {CreButtonsModule} from '../shared/components/buttons/buttons.module'; +import {RecipeAdd, RecipeForm} from './recipes'; @NgModule({ - declarations: [ListComponent, AddComponent, EditComponent, ExploreComponent, RecipeInfoComponent, MixTableComponent, StepListComponent, StepTableComponent, MixEditorComponent, UnitSelectorComponent, MixAddComponent, MixEditComponent, ImagesEditorComponent, MixesCardComponent], + declarations: [ + ListComponent, + EditComponent, + ExploreComponent, + RecipeInfoComponent, + MixTableComponent, + StepListComponent, + StepTableComponent, + MixEditorComponent, + UnitSelectorComponent, + MixAddComponent, + MixEditComponent, + ImagesEditorComponent, + MixesCardComponent, + RecipeForm, + RecipeAdd + ], exports: [ UnitSelectorComponent ], imports: [ - ColorsRoutingModule, + RecipesRoutingModule, SharedModule, MatExpansionModule, FormsModule, - MatSortModule + MatSortModule, + CreInputsModule, + CreButtonsModule ] }) -export class ColorsModule { +export class RecipesModule { } diff --git a/src/app/modules/recipes/recipes.ts b/src/app/modules/recipes/recipes.ts new file mode 100644 index 0000000..b6b6e75 --- /dev/null +++ b/src/app/modules/recipes/recipes.ts @@ -0,0 +1,119 @@ +import {ErrorHandlingComponent, SubscribingComponent} from '../shared/components/subscribing.component'; +import {Observable} from 'rxjs'; +import {ComboBoxEntry} from '../shared/components/inputs/inputs'; +import {map, tap} from 'rxjs/operators'; +import {RecipeService} from './services/recipe.service'; +import {CompanyService} from '../company/service/company.service'; +import {AppState} from '../shared/app-state'; +import {ErrorService} from '../shared/service/error.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {FormControl, Validators} from '@angular/forms'; +import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {Recipe} from '../shared/model/recipe.model'; +import {AccountService} from '../accounts/services/account.service'; +import {Permission} from '../shared/model/user'; + +@Component({ + selector: 'cre-recipe-add', + templateUrl: 'add.html' +}) +export class RecipeAdd extends ErrorHandlingComponent { + controls: any + companyEntries$: Observable = 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({ + selector: 'recipe-form', + templateUrl: 'form.html' +}) +export class RecipeForm extends SubscribingComponent { + @Input() recipe: Recipe | null + + @Output() submitForm = new EventEmitter(); + + controls: any + companyEntries$: Observable + hasCompanies = true + + constructor( + private companyService: CompanyService, + private accountService: AccountService, + errorService: ErrorService, + activatedRoute: ActivatedRoute, + router: Router, + ) { + super(errorService, activatedRoute, router) + } + + ngOnInit() { + super.ngOnInit(); + + this.fetchCompanies() + + this.controls = { + name: new FormControl(null, Validators.required), + description: new FormControl(null, Validators.required), + color: new FormControl('#ffffff', Validators.required), + gloss: new FormControl(0, Validators.compose([Validators.required, Validators.min(0), Validators.max(100)])), + sample: new FormControl(null, Validators.compose([Validators.required, Validators.min(0)])), + approbationDate: new FormControl(null), + remark: new FormControl(null), + company: new FormControl(null, Validators.required) + } + } + + private fetchCompanies() { + this.companyEntries$ = this.companyService.all.pipe( + tap(companies => this.hasCompanies = companies.length > 0), + map(companies => companies.map(c => new ComboBoxEntry(c.id, c.name))), + ) + } + + submit() { + this.submitForm.emit({ + id: this.recipe?.id, + name: this.controls.name.value, + description: this.controls.description.value, + color: this.controls.color.value, + gloss: this.controls.gloss.value, + sample: this.controls.sample.value, + approbationDate: this.controls.approbationDate.value, + remark: this.controls.remark.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 { + return this.accountService.hasPermission(Permission.EDIT_COMPANIES) + } +} diff --git a/src/app/modules/colors/services/mix.service.ts b/src/app/modules/recipes/services/mix.service.ts similarity index 100% rename from src/app/modules/colors/services/mix.service.ts rename to src/app/modules/recipes/services/mix.service.ts diff --git a/src/app/modules/colors/services/recipe-image.service.ts b/src/app/modules/recipes/services/recipe-image.service.ts similarity index 100% rename from src/app/modules/colors/services/recipe-image.service.ts rename to src/app/modules/recipes/services/recipe-image.service.ts diff --git a/src/app/modules/recipes/services/recipe.service.ts b/src/app/modules/recipes/services/recipe.service.ts new file mode 100644 index 0000000..b3d2670 --- /dev/null +++ b/src/app/modules/recipes/services/recipe.service.ts @@ -0,0 +1,89 @@ +import {Injectable} from '@angular/core' +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 {Company} from '../../shared/model/company.model'; + +@Injectable({ + providedIn: 'root' +}) +export class RecipeService { + constructor( + private api: ApiService + ) { + } + + get all(): Observable { + return this.api.get('/recipe') + } + + getAllByName(name: string): Observable { + return this.api.get(`/recipe?name=${name}`) + } + + get allByCompany(): Observable> { + return this.all.pipe(map(recipes => { + const map = new Map() + recipes.forEach(r => { + if (!map.has(r.company.id)) { + map.set(r.company.id, []) + } + map.get(r.company.id).push(r) + }) + return map + })) + } + + getById(id: number): Observable { + return this.api.get(`/recipe/${id}`) + } + + save(recipe: Recipe): Observable { + const body = { + ...recipe, + companyId: recipe.company + } + + return this.api.post('/recipe', body) + } + + 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) + } + + updateExplorerModifications(id: number, notes: Map, mixesLocationChange: Map): Observable { + const body = { + recipeId: id, + notes: [], + mixesLocation: [] + } + + 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) + } + + delete(id: number): Observable { + return this.api.delete(`/recipe/${id}`) + } +} diff --git a/src/app/modules/shared/components/alerts/alerts.ts b/src/app/modules/shared/components/alerts/alerts.ts index e150819..e31da46 100644 --- a/src/app/modules/shared/components/alerts/alerts.ts +++ b/src/app/modules/shared/components/alerts/alerts.ts @@ -1,8 +1,9 @@ -import {Component} from '@angular/core'; +import {Component, ViewEncapsulation} from '@angular/core'; @Component({ selector: 'cre-warning-alert', - templateUrl: 'alerts.html' + templateUrl: 'alerts.html', + encapsulation: ViewEncapsulation.None }) export class WarningAlert { diff --git a/src/app/modules/shared/components/forms/forms.sass b/src/app/modules/shared/components/forms/forms.sass index fffedc8..1a3fb08 100644 --- a/src/app/modules/shared/components/forms/forms.sass +++ b/src/app/modules/shared/components/forms/forms.sass @@ -1,8 +1,12 @@ cre-form display: block + width: max-content + min-width: 50rem + margin-top: 3rem mat-card width: inherit + min-width: inherit cre-form-actions display: flex diff --git a/src/app/modules/shared/components/forms/forms.ts b/src/app/modules/shared/components/forms/forms.ts index 5770d23..98a556c 100644 --- a/src/app/modules/shared/components/forms/forms.ts +++ b/src/app/modules/shared/components/forms/forms.ts @@ -42,7 +42,7 @@ export class CreFormComponent implements OnInit { } get hasActions(): boolean { - return this.formActions === true + return !!this.formActions } get invalid(): boolean { diff --git a/src/app/modules/shared/components/inputs/autocomplete.html b/src/app/modules/shared/components/inputs/autocomplete.html index bc21b24..760d6f4 100644 --- a/src/app/modules/shared/components/inputs/autocomplete.html +++ b/src/app/modules/shared/components/inputs/autocomplete.html @@ -24,7 +24,7 @@ [ngTemplateOutletContext]="{errors: control.errors}"> - + {{option}} diff --git a/src/app/modules/shared/components/inputs/chips-combo-box.html b/src/app/modules/shared/components/inputs/chips-combo-box.html index 443ff0c..f454ad3 100644 --- a/src/app/modules/shared/components/inputs/chips-combo-box.html +++ b/src/app/modules/shared/components/inputs/chips-combo-box.html @@ -30,7 +30,7 @@ - + {{option.display ? option.display : option.value}} diff --git a/src/app/modules/shared/components/inputs/combo-box.html b/src/app/modules/shared/components/inputs/combo-box.html index 5170f8c..7df0d9f 100644 --- a/src/app/modules/shared/components/inputs/combo-box.html +++ b/src/app/modules/shared/components/inputs/combo-box.html @@ -4,19 +4,20 @@ matInput type="text" [required]="required" - [formControl]="control" + [formControl]="internalControl" [matAutocomplete]="auto"> - - Ce champ est requis + + Cette valeur est invalide + Ce champ est requis + [ngTemplateOutletContext]="{errors: internalControl.errors}"> - - {{option.value}} + + {{entry.display || entry.value}} diff --git a/src/app/modules/shared/components/inputs/input.html b/src/app/modules/shared/components/inputs/input.html index 2bf813e..7b5f60f 100644 --- a/src/app/modules/shared/components/inputs/input.html +++ b/src/app/modules/shared/components/inputs/input.html @@ -5,6 +5,7 @@ @@ -13,6 +14,7 @@ diff --git a/src/app/modules/shared/components/inputs/inputs.module.ts b/src/app/modules/shared/components/inputs/inputs.module.ts index 1797478..aeddff9 100644 --- a/src/app/modules/shared/components/inputs/inputs.module.ts +++ b/src/app/modules/shared/components/inputs/inputs.module.ts @@ -4,7 +4,7 @@ import { CreChipComboBoxComponent, CreChipInputComponent, CreComboBoxComponent, CreFileInputComponent, - CreInputComponent, CrePeriodInputComponent + CreInputComponent, CrePeriodInputComponent, CreSliderInputComponent } from './inputs' import {MatInputModule} from '@angular/material/input' import {MatIconModule} from '@angular/material/icon' @@ -17,6 +17,7 @@ import {MatChipsModule} from '@angular/material/chips' import {CreButtonsModule} from '../buttons/buttons.module' import {MatCheckboxModule} from '@angular/material/checkbox' import {MatSelectModule} from '@angular/material/select' +import {MatSliderModule} from '@angular/material/slider'; @NgModule({ declarations: [ @@ -27,7 +28,8 @@ import {MatSelectModule} from '@angular/material/select' CreChipComboBoxComponent, CreFileInputComponent, CreCheckboxInputComponent, - CrePeriodInputComponent + CrePeriodInputComponent, + CreSliderInputComponent ], imports: [ MatInputModule, @@ -42,6 +44,7 @@ import {MatSelectModule} from '@angular/material/select' CreButtonsModule, MatCheckboxModule, MatSelectModule, + MatSliderModule, ], exports: [ CreInputComponent, @@ -51,7 +54,8 @@ import {MatSelectModule} from '@angular/material/select' CreAutocompleteInputComponent, CreFileInputComponent, CreCheckboxInputComponent, - CrePeriodInputComponent + CrePeriodInputComponent, + CreSliderInputComponent ] }) export class CreInputsModule { diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts index dc7204e..e080f72 100644 --- a/src/app/modules/shared/components/inputs/inputs.ts +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -22,7 +22,7 @@ import {MatAutocomplete, MatAutocompleteSelectedEvent} from '@angular/material/a @Directive() abstract class _CreInputBase { - @Input() control: AbstractControl | null + @Input() control: FormControl | null @Input() label: string @Input() value @Input() disabled = false @@ -55,9 +55,12 @@ export class CreInputComponent extends _CreInputBase implements AfterViewInit { element.type = this.type element.step = this.step.toString() element.placeholder = this.placeholder - element.required = this.required element.autocomplete = this.autocomplete ? 'on' : 'off' } + + get isFieldRequired(): boolean { + return this.control ? this.control.validator && this.control.validator({} as AbstractControl)?.required : this.required + } } @Component({ @@ -70,7 +73,7 @@ export class CreAutocompleteInputComponent { @Input() label: string @Input() icon: string @Input() required = true - @Input() options: Observable + @Input() entries: Observable @Input() value @Output() valueChange = new EventEmitter() @@ -132,14 +135,70 @@ export class CreChipInputComponent implements OnInit { templateUrl: 'combo-box.html', encapsulation: ViewEncapsulation.None }) -export class CreComboBoxComponent { +export class CreComboBoxComponent implements OnInit { @Input() control: AbstractControl @Input() label: string @Input() icon: string @Input() required = true - @Input() options: Observable + @Input() entries: Observable @ContentChild(TemplateRef) errors: TemplateRef + + internalControl: FormControl + validValue = false + + private _destroy$ = new Subject(); + private _entries: ComboBoxEntry[] + + ngOnInit() { + this.entries.pipe(takeUntil(this._destroy$)) + .subscribe({ + next: entries => { + this._entries = entries + + this.internalControl.setValue(this.findEntryByKey(this.control.value)?.value) + } + }) + + this.internalControl = new FormControl(null, Validators.compose([this.control.validator, this.valueValidator()])) + this.internalControl.valueChanges.pipe(takeUntil(this._destroy$)) + .subscribe({ + next: value => { + if (this.internalControl.valid) { + this.control.setValue(this.findEntryByValue(value).key) + } else { + this.control.setValue(null) + } + } + }) + } + + private findEntryByKey(key: any): ComboBoxEntry | null { + const found = this._entries.filter(e => e.key === key) + if (found.length <= 0) { + return null + } + return found[0] + } + + private findEntryByValue(value: any): ComboBoxEntry | null { + const found = this._entries.filter(e => e.value === value) + if (found.length <= 0) { + return null + } + return found[0] + } + + private existsEntryByValue(value: any): boolean { + return this._entries && this._entries.filter(o => o.value === value).length > 0 + } + + private valueValidator(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + const valid = this.existsEntryByValue(control.value) + return valid ? null : {invalidValue: {value: control.value}} + } + } } @Component({ @@ -148,25 +207,27 @@ export class CreComboBoxComponent { encapsulation: ViewEncapsulation.None }) export class CreChipComboBoxComponent extends CreChipInputComponent implements OnDestroy { - @Input() options: Observable + @Input() entries: Observable @ContentChild(TemplateRef) errors: TemplateRef @ViewChild('chipInput') chipInput: ElementRef @ViewChild('auto') matAutocomplete: MatAutocomplete - filteredOptions: Observable + filteredEntries: Observable - private _options: ComboBoxEntry[] + private _entries: ComboBoxEntry[] private _destroy$ = new Subject() ngOnInit() { super.ngOnInit() - this.options.pipe(takeUntil(this._destroy$)) - .subscribe({next: options => this._options = options}) + this.entries.pipe(takeUntil(this._destroy$)) + .subscribe({ + next: entries => this._entries = entries + }) - this.filteredOptions = this.inputControl.valueChanges.pipe( - map((query: string | null) => query ? this._filter(query) : this._options.slice()) + this.filteredEntries = this.inputControl.valueChanges.pipe( + map((query: string | null) => query ? this._filter(query) : this._entries.slice()) ) } @@ -187,11 +248,11 @@ export class CreChipComboBoxComponent extends CreChipInputComponent implements O private _filter(query: string): ComboBoxEntry[] { const filterValue = query.toString().toLowerCase() - return this._options.filter(option => option.value.toString().toLowerCase().indexOf(filterValue) === 0) + return this._entries.filter(e => e.value.toString().toLowerCase().indexOf(filterValue) === 0) } private findValueByKey(key: any): any { - return this._options.filter(o => o.key === key)[0].value + return this._entries.filter(e => e.key === key)[0].value } } @@ -294,6 +355,24 @@ export class CrePeriodInputComponent implements OnInit { } } +@Component({ + selector: 'cre-slider-input', + templateUrl: 'slider.html' +}) +export class CreSliderInputComponent { + @Input() control: FormControl + @Input() label: string + @Input() min: number + @Input() max: number + @Input() step = 1 + @Input() percents = false + @Input() thumbLabel = true + + formatValueForDisplay(value: number): string { + return this.percents ? `${value}%` : value.toString() + } +} + export class ComboBoxEntry { constructor( public key: any, diff --git a/src/app/modules/shared/components/inputs/slider.html b/src/app/modules/shared/components/inputs/slider.html new file mode 100644 index 0000000..1873422 --- /dev/null +++ b/src/app/modules/shared/components/inputs/slider.html @@ -0,0 +1,13 @@ +
+

{{label}}

+ + +
diff --git a/src/app/modules/shared/model/recipe.model.ts b/src/app/modules/shared/model/recipe.model.ts index 2fb9e52..3b096e0 100644 --- a/src/app/modules/shared/model/recipe.model.ts +++ b/src/app/modules/shared/model/recipe.model.ts @@ -1,25 +1,21 @@ import {Material} from './material.model' -import {LocalDate} from 'js-joda' import {Company} from './company.model' import {Group} from './user' export class Recipe { - constructor( - public id: number, - public name: string, - public description: string, - public color: string, - public gloss: number, - public sample: number, - public approbationDate: string, - public approbationExpired: boolean, - public remark: string, - public company: Company, - public mixes: Mix[], - public groupsInformation: RecipeGroupInformation[], - public imagesUrls: string[] - ) { - } + public id: number + public name: string + public description: string + public color: string + public gloss: number + public sample: number + public approbationDate: string + public remark: string + public company: Company + public mixes: Mix[] + public approbationExpired: boolean + public groupsInformation: RecipeGroupInformation[] + public imagesUrls: string[] } export class RecipeGroupInformation { diff --git a/src/app/modules/touch-up-kit/components/finish.ts b/src/app/modules/touch-up-kit/components/finish.ts index d91f01b..09b2fd7 100644 --- a/src/app/modules/touch-up-kit/components/finish.ts +++ b/src/app/modules/touch-up-kit/components/finish.ts @@ -1,6 +1,6 @@ import {Component, Input} from '@angular/core' import {SubscribingComponent} from '../../shared/components/subscribing.component' -import {RecipeService} from '../../colors/services/recipe.service' +import {RecipeService} from '../../recipes/services/recipe.service' import {ErrorService} from '../../shared/service/error.service' import {ActivatedRoute, Router} from '@angular/router' import {Recipe} from '../../shared/model/recipe.model' diff --git a/src/app/modules/touch-up-kit/components/form.html b/src/app/modules/touch-up-kit/components/form.html index 999b820..a6dd9eb 100644 --- a/src/app/modules/touch-up-kit/components/form.html +++ b/src/app/modules/touch-up-kit/components/form.html @@ -5,7 +5,7 @@ @@ -18,7 +18,7 @@ diff --git a/src/app/modules/touch-up-kit/components/form.ts b/src/app/modules/touch-up-kit/components/form.ts index 0a77b7f..b9b5e51 100644 --- a/src/app/modules/touch-up-kit/components/form.ts +++ b/src/app/modules/touch-up-kit/components/form.ts @@ -3,7 +3,7 @@ import {chipListRequired, ComboBoxEntry, CreChipComboBoxComponent} from '../../s import {CreFormComponent} from '../../shared/components/forms/forms' import {TouchUpKitProductEditor} from './product-editor' import {FormControl, Validators} from '@angular/forms' -import {RecipeService} from '../../colors/services/recipe.service' +import {RecipeService} from '../../recipes/services/recipe.service' import {CompanyService} from '../../company/service/company.service' import {ErrorService} from '../../shared/service/error.service' import {ActivatedRoute, Router} from '@angular/router' diff --git a/src/app/modules/touch-up-kit/pages/touchupkit.ts b/src/app/modules/touch-up-kit/pages/touchupkit.ts index 57b3ed5..b9db2e4 100644 --- a/src/app/modules/touch-up-kit/pages/touchupkit.ts +++ b/src/app/modules/touch-up-kit/pages/touchupkit.ts @@ -7,7 +7,7 @@ import {AccountService} from '../../accounts/services/account.service' import {ErrorService} from '../../shared/service/error.service' import {ActivatedRoute, Router} from '@angular/router' import {Permission} from '../../shared/model/user' -import {RecipeService} from '../../colors/services/recipe.service' +import {RecipeService} from '../../recipes/services/recipe.service' import {AppState} from '../../shared/app-state' import {map} from 'rxjs/operators' import {LocalDate, Period} from 'js-joda' From 521db72f5ec48308e9081d1dd6d390cb9c7e7742 Mon Sep 17 00:00:00 2001 From: William Nolin Date: Tue, 14 Sep 2021 16:19:00 -0400 Subject: [PATCH 05/28] #14 Update recipe editor --- .../images-editor.component.html | 2 + .../mixes-card/mixes-card.component.html | 2 + src/app/modules/recipes/edit.html | 36 ++++ src/app/modules/recipes/form.html | 9 +- .../recipes/pages/edit/edit.component.html | 68 ------ .../recipes/pages/edit/edit.component.sass | 2 - .../recipes/pages/edit/edit.component.ts | 186 ---------------- .../modules/recipes/recipes-routing.module.ts | 13 +- src/app/modules/recipes/recipes.module.ts | 11 +- src/app/modules/recipes/recipes.sass | 6 + src/app/modules/recipes/recipes.ts | 199 +++++++++++++----- .../recipes/services/recipe.service.ts | 9 +- .../shared/components/inputs/inputs.ts | 13 +- src/app/modules/shared/utils/map.utils.ts | 4 + 14 files changed, 226 insertions(+), 334 deletions(-) create mode 100644 src/app/modules/recipes/edit.html delete mode 100644 src/app/modules/recipes/pages/edit/edit.component.html delete mode 100644 src/app/modules/recipes/pages/edit/edit.component.sass delete mode 100644 src/app/modules/recipes/pages/edit/edit.component.ts create mode 100644 src/app/modules/recipes/recipes.sass diff --git a/src/app/modules/recipes/components/images-editor/images-editor.component.html b/src/app/modules/recipes/components/images-editor/images-editor.component.html index e07f7b8..97e9424 100644 --- a/src/app/modules/recipes/components/images-editor/images-editor.component.html +++ b/src/app/modules/recipes/components/images-editor/images-editor.component.html @@ -4,6 +4,8 @@
+

Aucune image n'est associée à cette couleur

+
diff --git a/src/app/modules/recipes/components/mixes-card/mixes-card.component.html b/src/app/modules/recipes/components/mixes-card/mixes-card.component.html index b6766df..c8a093a 100644 --- a/src/app/modules/recipes/components/mixes-card/mixes-card.component.html +++ b/src/app/modules/recipes/components/mixes-card/mixes-card.component.html @@ -3,6 +3,8 @@ Mélanges +

Il n'y a aucun mélange dans cette couleur

+ + + + Retour + + + + Supprimer + Enregistrer + + + +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ + + diff --git a/src/app/modules/recipes/form.html b/src/app/modules/recipes/form.html index a00dcf1..7f72041 100644 --- a/src/app/modules/recipes/form.html +++ b/src/app/modules/recipes/form.html @@ -1,12 +1,13 @@ -
- +
+

Il n'y a actuellement aucune bannière enregistrée dans le système.

Vous pouvez en créer une ici.

- Ajouter une recette + Ajouter une couleur + Modifier la couleur {{recipe.name}} @@ -17,7 +18,7 @@ - + Retour Enregistrer diff --git a/src/app/modules/recipes/pages/edit/edit.component.html b/src/app/modules/recipes/pages/edit/edit.component.html deleted file mode 100644 index 81461f8..0000000 --- a/src/app/modules/recipes/pages/edit/edit.component.html +++ /dev/null @@ -1,68 +0,0 @@ -
-
-
-
- - - -
- - Unités - - Millilitres - Litres - Gallons - - -
-
-
- -
-
- - -
- -
- -
- -
- - -
- -
- -
-
-
- - - diff --git a/src/app/modules/recipes/pages/edit/edit.component.sass b/src/app/modules/recipes/pages/edit/edit.component.sass deleted file mode 100644 index 2533b3c..0000000 --- a/src/app/modules/recipes/pages/edit/edit.component.sass +++ /dev/null @@ -1,2 +0,0 @@ -.recipe-wrapper > div - margin: 0 3rem 3rem diff --git a/src/app/modules/recipes/pages/edit/edit.component.ts b/src/app/modules/recipes/pages/edit/edit.component.ts deleted file mode 100644 index ab663dc..0000000 --- a/src/app/modules/recipes/pages/edit/edit.component.ts +++ /dev/null @@ -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() - 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): 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/recipes/recipes-routing.module.ts b/src/app/modules/recipes/recipes-routing.module.ts index a29258a..95fd2a9 100644 --- a/src/app/modules/recipes/recipes-routing.module.ts +++ b/src/app/modules/recipes/recipes-routing.module.ts @@ -1,11 +1,10 @@ import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; -import {ListComponent} from "./pages/list/list.component"; -import {EditComponent} from "./pages/edit/edit.component"; -import {ExploreComponent} from "./pages/explore/explore.component"; -import {MixEditComponent} from "./pages/mix/mix-edit/mix-edit.component"; -import {MixAddComponent} from "./pages/mix/mix-add/mix-add.component"; -import {RecipeAdd} from './recipes'; +import {ListComponent} from './pages/list/list.component'; +import {ExploreComponent} from './pages/explore/explore.component'; +import {MixEditComponent} from './pages/mix/mix-edit/mix-edit.component'; +import {MixAddComponent} from './pages/mix/mix-add/mix-add.component'; +import {RecipeAdd, RecipeEdit} from './recipes'; const routes: Routes = [{ path: 'list', @@ -15,7 +14,7 @@ const routes: Routes = [{ component: RecipeAdd }, { path: 'edit/:id', - component: EditComponent + component: RecipeEdit }, { path: 'add/mix/:recipeId', component: MixAddComponent diff --git a/src/app/modules/recipes/recipes.module.ts b/src/app/modules/recipes/recipes.module.ts index 3170cd2..71aacfe 100644 --- a/src/app/modules/recipes/recipes.module.ts +++ b/src/app/modules/recipes/recipes.module.ts @@ -3,7 +3,6 @@ import {NgModule} from '@angular/core' import {RecipesRoutingModule} from './recipes-routing.module' import {SharedModule} from '../shared/shared.module' import {ListComponent} from './pages/list/list.component' -import {EditComponent} from './pages/edit/edit.component' import {MatExpansionModule} from '@angular/material/expansion' import {FormsModule} from '@angular/forms' import {ExploreComponent} from './pages/explore/explore.component' @@ -20,13 +19,13 @@ import {MixesCardComponent} from './components/mixes-card/mixes-card.component' import {MatSortModule} from '@angular/material/sort' import {CreInputsModule} from '../shared/components/inputs/inputs.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({ declarations: [ ListComponent, - EditComponent, ExploreComponent, RecipeInfoComponent, MixTableComponent, @@ -39,7 +38,8 @@ import {RecipeAdd, RecipeForm} from './recipes'; ImagesEditorComponent, MixesCardComponent, RecipeForm, - RecipeAdd + RecipeAdd, + RecipeEdit ], exports: [ UnitSelectorComponent @@ -51,7 +51,8 @@ import {RecipeAdd, RecipeForm} from './recipes'; FormsModule, MatSortModule, CreInputsModule, - CreButtonsModule + CreButtonsModule, + CreActionBarModule ] }) export class RecipesModule { diff --git a/src/app/modules/recipes/recipes.sass b/src/app/modules/recipes/recipes.sass new file mode 100644 index 0000000..d19072a --- /dev/null +++ b/src/app/modules/recipes/recipes.sass @@ -0,0 +1,6 @@ +.recipe-wrapper > section + margin: 0 3rem 3rem + +cre-form + margin-top: 0 !important + diff --git a/src/app/modules/recipes/recipes.ts b/src/app/modules/recipes/recipes.ts index b6b6e75..19c0c3d 100644 --- a/src/app/modules/recipes/recipes.ts +++ b/src/app/modules/recipes/recipes.ts @@ -1,56 +1,27 @@ 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 {map, tap} from 'rxjs/operators'; import {RecipeService} from './services/recipe.service'; import {CompanyService} from '../company/service/company.service'; 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 {FormControl, Validators} from '@angular/forms'; -import {Component, EventEmitter, Input, Output} from '@angular/core'; -import {Recipe} from '../shared/model/recipe.model'; +import {Component, EventEmitter, Input, Output, ViewChild, ViewEncapsulation} from '@angular/core'; +import {Recipe, recipeMixCount, RecipeStep, recipeStepCount} from '../shared/model/recipe.model'; import {AccountService} from '../accounts/services/account.service'; import {Permission} from '../shared/model/user'; - -@Component({ - selector: 'cre-recipe-add', - templateUrl: 'add.html' -}) -export class RecipeAdd extends ErrorHandlingComponent { - controls: any - companyEntries$: Observable = 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}`) - ) - } -} +import {AlertService} from '../shared/service/alert.service'; +import {GroupService} from '../groups/services/group.service'; +import {StepTableComponent} from './components/step-table/step-table.component'; +import {anyMap} from '../shared/utils/map.utils'; @Component({ selector: 'recipe-form', - templateUrl: 'form.html' + templateUrl: 'form.html', + styleUrls: ['recipes.sass'], + encapsulation: ViewEncapsulation.None }) export class RecipeForm extends SubscribingComponent { @Input() recipe: Recipe | null @@ -77,14 +48,14 @@ export class RecipeForm extends SubscribingComponent { this.fetchCompanies() this.controls = { - name: new FormControl(null, Validators.required), - description: new FormControl(null, Validators.required), - color: new FormControl('#ffffff', Validators.required), - gloss: new FormControl(0, Validators.compose([Validators.required, Validators.min(0), Validators.max(100)])), - sample: new FormControl(null, Validators.compose([Validators.required, Validators.min(0)])), - approbationDate: new FormControl(null), - remark: new FormControl(null), - company: new FormControl(null, Validators.required) + name: new FormControl(this.recipe?.name, Validators.required), + description: new FormControl(this.recipe?.description, Validators.required), + color: new FormControl(this.recipe?.color ?? '#ffffff', Validators.required), + gloss: new FormControl(this.recipe?.gloss ?? 0, Validators.compose([Validators.required, Validators.min(0), Validators.max(100)])), + sample: new FormControl(this.recipe?.sample, Validators.compose([Validators.required, Validators.min(0)])), + approbationDate: new FormControl(this.recipe?.approbationDate), + remark: new FormControl(this.recipe?.remark), + company: new FormControl({value: this.recipe?.company.id, disabled: !!this.recipe}, Validators.required) } } @@ -96,8 +67,12 @@ export class RecipeForm extends SubscribingComponent { } submit() { - this.submitForm.emit({ - id: this.recipe?.id, + this.submitForm.emit(this.updatedRecipe) + } + + get updatedRecipe(): Recipe { + return { + ...this.recipe, name: this.controls.name.value, description: this.controls.description.value, color: this.controls.color.value, @@ -106,14 +81,128 @@ export class RecipeForm extends SubscribingComponent { approbationDate: this.controls.approbationDate.value, remark: this.controls.remark.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 { 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() + + 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): boolean { + return !anyMap(steps, (groupId, steps) => !!steps.find(s => s.position === 0)) + } +} diff --git a/src/app/modules/recipes/services/recipe.service.ts b/src/app/modules/recipes/services/recipe.service.ts index b3d2670..4a99612 100644 --- a/src/app/modules/recipes/services/recipe.service.ts +++ b/src/app/modules/recipes/services/recipe.service.ts @@ -48,11 +48,10 @@ 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: Map) { - const body = {id, name, description, color, gloss, sample, remark, steps: []} - if (approbationDate) { - // @ts-ignore - body.approbationDate = approbationDate + update(recipe: Recipe, steps: Map) { + const body = { + ...recipe, + steps: [] } steps.forEach((groupSteps, groupId) => { diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts index e080f72..58c494a 100644 --- a/src/app/modules/shared/components/inputs/inputs.ts +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -156,11 +156,20 @@ export class CreComboBoxComponent implements OnInit { next: 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$)) .subscribe({ next: value => { diff --git a/src/app/modules/shared/utils/map.utils.ts b/src/app/modules/shared/utils/map.utils.ts index ba99aec..dd43b65 100644 --- a/src/app/modules/shared/utils/map.utils.ts +++ b/src/app/modules/shared/utils/map.utils.ts @@ -1,3 +1,7 @@ +export function anyMap(map: Map, predicate: (key: K, value: V) => boolean): boolean { + return filterMap(map, predicate).size > 0 +} + export function filterMap(map: Map, predicate: (key: K, value: V) => boolean): Map { const filteredMap = new Map() map.forEach((value, key) => { From a96062a91f106947fb0eab68a3cabda07d006b51 Mon Sep 17 00:00:00 2001 From: William Nolin Date: Tue, 21 Sep 2021 07:40:36 -0400 Subject: [PATCH 06/28] #14 Update recipe explorer --- .../images-editor.component.html | 2 +- .../step-list/step-list.component.html | 2 +- .../pages/explore/explore.component.html | 70 +++++----------- .../pages/explore/explore.component.ts | 79 ++++++++++++++----- src/app/modules/recipes/recipes.ts | 6 +- .../recipes/services/recipe.service.ts | 1 - .../components/action-bar/action-group.html | 7 +- .../shared/components/inputs/inputs.module.ts | 10 ++- .../shared/components/inputs/inputs.ts | 43 +++++++--- .../shared/components/inputs/select.html | 8 ++ .../shared/components/inputs/textarea.html | 9 +++ .../modules/touch-up-kit/components/form.ts | 4 +- 12 files changed, 145 insertions(+), 96 deletions(-) create mode 100644 src/app/modules/shared/components/inputs/select.html create mode 100644 src/app/modules/shared/components/inputs/textarea.html diff --git a/src/app/modules/recipes/components/images-editor/images-editor.component.html b/src/app/modules/recipes/components/images-editor/images-editor.component.html index 97e9424..abd0574 100644 --- a/src/app/modules/recipes/components/images-editor/images-editor.component.html +++ b/src/app/modules/recipes/components/images-editor/images-editor.component.html @@ -4,7 +4,7 @@
-

Aucune image n'est associée à cette couleur

+

Aucune image n'est associée à cette couleur

diff --git a/src/app/modules/recipes/components/step-list/step-list.component.html b/src/app/modules/recipes/components/step-list/step-list.component.html index c53850d..daa579e 100644 --- a/src/app/modules/recipes/components/step-list/step-list.component.html +++ b/src/app/modules/recipes/components/step-list/step-list.component.html @@ -3,7 +3,7 @@ Étapes - + {{step.position}}.{{step.message}} diff --git a/src/app/modules/recipes/pages/explore/explore.component.html b/src/app/modules/recipes/pages/explore/explore.component.html index 93b3b3e..8d8f714 100644 --- a/src/app/modules/recipes/pages/explore/explore.component.html +++ b/src/app/modules/recipes/pages/explore/explore.component.html @@ -1,60 +1,26 @@
-
-
-
- - - -
- -
+ + + + Retour - - Groupe - - - {{group.name}} - - - -
-
+ + + + + + + + Version Excel + + Enregistrer + + + -
- - - Note - - -

{{selectedGroupNote}}

-
- -
+
() selectedGroupId: number | null @@ -33,6 +40,12 @@ export class ExploreComponent extends ErrorHandlingComponent { deductedMixId: number | null + groupControl: FormControl + noteControl: FormControl + groupEntries$ = this.groupService.all.pipe(map(groups => { + return groups.map(group => new CreInputEntry(group.id, group.name)) + })) + errorHandlers: ErrorHandler[] = [{ filter: error => error.type === 'notfound-recipe-id', consumer: error => this.urlUtils.navigateTo('/color/list') @@ -42,6 +55,9 @@ export class ExploreComponent extends ErrorHandlingComponent { messageProducer: () => 'Certains produit ne sont pas en quantité suffisante dans l\'inventaire' }] + private _recipe: Recipe | null + private _notePlaceholder = !this.canEditRecipesPublicData ? 'N/A' : '' + constructor( private recipeService: RecipeService, private inventoryService: InventoryService, @@ -62,18 +78,30 @@ export class ExploreComponent extends ErrorHandlingComponent { this.selectedGroupId = this.loggedInUserGroupId - const id = parseInt(this.activatedRoute.snapshot.paramMap.get('id')) + this.fetchRecipe() + + this.groupControl = new FormControl(this.selectedGroupId) + this.subscribe( + this.groupControl.valueChanges, + groupId => { + this.selectedGroupId = groupId + this.noteControl.setValue(this.selectedGroupNote, {emitEvent: false}) + } + ) + + this.noteControl = new FormControl({value: this._notePlaceholder, disabled: !this.canEditRecipesPublicData}) + this.subscribe( + this.noteControl.valueChanges, + _ => this.hasModifications = true + ) + } + + fetchRecipe() { + const recipeId = parseInt(this.activatedRoute.snapshot.paramMap.get('id')) this.subscribeEntityById( this.recipeService, - id, - r => { - this.recipe = r - this.appState.title = r.name - - if (recipeMixCount(this.recipe) <= 0 || recipeStepCount(this.recipe) <= 0) { - this.alertService.pushWarning('Cette recette n\'est pas complète') - } - } + recipeId, + recipe => this.recipe = recipe ) } @@ -128,11 +156,24 @@ export class ExploreComponent extends ErrorHandlingComponent { subscribeDeductMix(observable: Observable) { this.subscribe( observable, - () => this.alertService.pushSuccess('Les quantités quantités ont été déduites de l\'inventaire'), + () => this.alertService.pushSuccess('Les quantités ont été déduites de l\'inventaire'), true ) } + get recipe(): Recipe { + return this._recipe + } + + set recipe(recipe: Recipe) { + this._recipe = recipe + this.appState.title = recipe.name + + if (recipeMixCount(recipe) <= 0 || recipeStepCount(recipe) <= 0) { + this.alertService.pushWarning('Cette recette n\'est pas complète') + } + } + get loggedInUserGroupId(): number { return this.appState.authenticatedUser.group?.id } @@ -141,11 +182,7 @@ export class ExploreComponent extends ErrorHandlingComponent { 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) + return this.groupsNote.get(this.selectedGroupId) ?? this._notePlaceholder } get canEditRecipesPublicData(): boolean { @@ -160,7 +197,9 @@ export class ExploreComponent extends ErrorHandlingComponent { }) this.groupsNote.forEach((content, groupId) => { - updatedNotes.set(groupId, content) + if (content) { + updatedNotes.set(groupId, content) + } }) return updatedNotes diff --git a/src/app/modules/recipes/recipes.ts b/src/app/modules/recipes/recipes.ts index 19c0c3d..1be6565 100644 --- a/src/app/modules/recipes/recipes.ts +++ b/src/app/modules/recipes/recipes.ts @@ -1,6 +1,6 @@ import {ErrorHandlingComponent, SubscribingComponent} from '../shared/components/subscribing.component'; import {Observable, Subject} from 'rxjs'; -import {ComboBoxEntry} from '../shared/components/inputs/inputs'; +import {CreInputEntry} from '../shared/components/inputs/inputs'; import {map, tap} from 'rxjs/operators'; import {RecipeService} from './services/recipe.service'; import {CompanyService} from '../company/service/company.service'; @@ -29,7 +29,7 @@ export class RecipeForm extends SubscribingComponent { @Output() submitForm = new EventEmitter(); controls: any - companyEntries$: Observable + companyEntries$: Observable hasCompanies = true constructor( @@ -62,7 +62,7 @@ export class RecipeForm extends SubscribingComponent { private fetchCompanies() { this.companyEntries$ = this.companyService.all.pipe( tap(companies => this.hasCompanies = companies.length > 0), - map(companies => companies.map(c => new ComboBoxEntry(c.id, c.name))), + map(companies => companies.map(c => new CreInputEntry(c.id, c.name))), ) } diff --git a/src/app/modules/recipes/services/recipe.service.ts b/src/app/modules/recipes/services/recipe.service.ts index 4a99612..4554569 100644 --- a/src/app/modules/recipes/services/recipe.service.ts +++ b/src/app/modules/recipes/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 {Company} from '../../shared/model/company.model'; @Injectable({ providedIn: 'root' diff --git a/src/app/modules/shared/components/action-bar/action-group.html b/src/app/modules/shared/components/action-bar/action-group.html index dfdbcc7..01b5f5d 100644 --- a/src/app/modules/shared/components/action-bar/action-group.html +++ b/src/app/modules/shared/components/action-bar/action-group.html @@ -1,3 +1,6 @@ -
- +
+
+ +
+
diff --git a/src/app/modules/shared/components/inputs/inputs.module.ts b/src/app/modules/shared/components/inputs/inputs.module.ts index aeddff9..e45c685 100644 --- a/src/app/modules/shared/components/inputs/inputs.module.ts +++ b/src/app/modules/shared/components/inputs/inputs.module.ts @@ -4,7 +4,7 @@ import { CreChipComboBoxComponent, CreChipInputComponent, CreComboBoxComponent, CreFileInputComponent, - CreInputComponent, CrePeriodInputComponent, CreSliderInputComponent + CreInputComponent, CrePeriodInputComponent, CreSelectComponent, CreSliderInputComponent, CreTextareaComponent } from './inputs' import {MatInputModule} from '@angular/material/input' import {MatIconModule} from '@angular/material/icon' @@ -29,7 +29,9 @@ import {MatSliderModule} from '@angular/material/slider'; CreFileInputComponent, CreCheckboxInputComponent, CrePeriodInputComponent, - CreSliderInputComponent + CreSliderInputComponent, + CreTextareaComponent, + CreSelectComponent ], imports: [ MatInputModule, @@ -55,7 +57,9 @@ import {MatSliderModule} from '@angular/material/slider'; CreFileInputComponent, CreCheckboxInputComponent, CrePeriodInputComponent, - CreSliderInputComponent + CreSliderInputComponent, + CreTextareaComponent, + CreSelectComponent ] }) export class CreInputsModule { diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts index 58c494a..fb038e9 100644 --- a/src/app/modules/shared/components/inputs/inputs.ts +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -63,6 +63,19 @@ export class CreInputComponent extends _CreInputBase implements AfterViewInit { } } +@Component({ + selector: 'cre-textarea', + templateUrl: 'textarea.html', + encapsulation: ViewEncapsulation.None +}) +export class CreTextareaComponent { + @Input() label: string + @Input() control: FormControl + @Input() cols = 40 + @Input() rows = 3 + @Input() placeholder: string | null +} + @Component({ selector: 'cre-autocomplete-input', templateUrl: 'autocomplete.html', @@ -140,7 +153,7 @@ export class CreComboBoxComponent implements OnInit { @Input() label: string @Input() icon: string @Input() required = true - @Input() entries: Observable + @Input() entries: Observable @ContentChild(TemplateRef) errors: TemplateRef @@ -148,7 +161,7 @@ export class CreComboBoxComponent implements OnInit { validValue = false private _destroy$ = new Subject(); - private _entries: ComboBoxEntry[] + private _entries: CreInputEntry[] ngOnInit() { this.entries.pipe(takeUntil(this._destroy$)) @@ -160,7 +173,7 @@ export class CreComboBoxComponent implements OnInit { this.internalControl.setValue(this.findEntryByKey(this.control.value)?.value) } - if (this.internalControl.disabled) { + if (this.control.disabled) { this.internalControl.disable() } } @@ -168,7 +181,7 @@ export class CreComboBoxComponent implements OnInit { this.internalControl = new FormControl({ value: null, - disabled: true + disabled: false }, Validators.compose([this.control.validator, this.valueValidator()])) this.internalControl.valueChanges.pipe(takeUntil(this._destroy$)) .subscribe({ @@ -182,7 +195,7 @@ export class CreComboBoxComponent implements OnInit { }) } - private findEntryByKey(key: any): ComboBoxEntry | null { + private findEntryByKey(key: any): CreInputEntry | null { const found = this._entries.filter(e => e.key === key) if (found.length <= 0) { return null @@ -190,7 +203,7 @@ export class CreComboBoxComponent implements OnInit { return found[0] } - private findEntryByValue(value: any): ComboBoxEntry | null { + private findEntryByValue(value: any): CreInputEntry | null { const found = this._entries.filter(e => e.value === value) if (found.length <= 0) { return null @@ -216,15 +229,15 @@ export class CreComboBoxComponent implements OnInit { encapsulation: ViewEncapsulation.None }) export class CreChipComboBoxComponent extends CreChipInputComponent implements OnDestroy { - @Input() entries: Observable + @Input() entries: Observable @ContentChild(TemplateRef) errors: TemplateRef @ViewChild('chipInput') chipInput: ElementRef @ViewChild('auto') matAutocomplete: MatAutocomplete - filteredEntries: Observable + filteredEntries: Observable - private _entries: ComboBoxEntry[] + private _entries: CreInputEntry[] private _destroy$ = new Subject() ngOnInit() { @@ -255,7 +268,7 @@ export class CreChipComboBoxComponent extends CreChipInputComponent implements O return this.selectedValues.length <= 0 } - private _filter(query: string): ComboBoxEntry[] { + private _filter(query: string): CreInputEntry[] { const filterValue = query.toString().toLowerCase() return this._entries.filter(e => e.value.toString().toLowerCase().indexOf(filterValue) === 0) } @@ -382,7 +395,15 @@ export class CreSliderInputComponent { } } -export class ComboBoxEntry { +@Component({ + selector: 'cre-select', + templateUrl: 'select.html' +}) +export class CreSelectComponent extends _CreInputBase { + @Input() entries: Observable +} + +export class CreInputEntry { constructor( public key: any, public value: any, diff --git a/src/app/modules/shared/components/inputs/select.html b/src/app/modules/shared/components/inputs/select.html new file mode 100644 index 0000000..6fd806b --- /dev/null +++ b/src/app/modules/shared/components/inputs/select.html @@ -0,0 +1,8 @@ + + {{label}} + + + {{entry.display || entry.value}} + + + diff --git a/src/app/modules/shared/components/inputs/textarea.html b/src/app/modules/shared/components/inputs/textarea.html new file mode 100644 index 0000000..18653c0 --- /dev/null +++ b/src/app/modules/shared/components/inputs/textarea.html @@ -0,0 +1,9 @@ + + {{label}} + + diff --git a/src/app/modules/touch-up-kit/components/form.ts b/src/app/modules/touch-up-kit/components/form.ts index b9b5e51..09c7248 100644 --- a/src/app/modules/touch-up-kit/components/form.ts +++ b/src/app/modules/touch-up-kit/components/form.ts @@ -1,5 +1,5 @@ import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core' -import {chipListRequired, ComboBoxEntry, CreChipComboBoxComponent} from '../../shared/components/inputs/inputs' +import {chipListRequired, CreInputEntry, CreChipComboBoxComponent} from '../../shared/components/inputs/inputs' import {CreFormComponent} from '../../shared/components/forms/forms' import {TouchUpKitProductEditor} from './product-editor' import {FormControl, Validators} from '@angular/forms' @@ -25,7 +25,7 @@ export class TouchUpKitForm extends SubscribingComponent { controls: any finish$ = this.recipeService.all.pipe( - map(recipes => recipes.map(recipe => new ComboBoxEntry(recipe.id, recipe.name, `${recipe.name} - ${recipe.company.name}`))) + map(recipes => recipes.map(recipe => new CreInputEntry(recipe.id, recipe.name, `${recipe.name} - ${recipe.company.name}`))) ) companies$ = this.companyService.all.pipe( map(companies => companies.map(company => company.name)) From c21dd8d0f9e047aa06a31104a5b2441676d14b3c Mon Sep 17 00:00:00 2001 From: William Nolin Date: Mon, 8 Nov 2021 01:26:31 -0500 Subject: [PATCH 07/28] Things --- docker-compose.yml | 4 +- src/app/modules/recipes/add.html | 11 +- .../mix-editor/mix-editor.component.html | 230 +++++++++--------- .../mix-editor/mix-editor.component.ts | 125 +++++----- .../explore.component.html => explore.html} | 0 .../explore.component.ts => explore.ts} | 36 +-- src/app/modules/recipes/form.html | 6 +- .../list/list.component.html => list.html} | 34 +-- .../{pages/list/list.component.ts => list.ts} | 48 ++-- .../pages/explore/explore.component.sass | 2 - .../recipes/pages/list/list.component.sass | 9 - .../modules/recipes/recipes-routing.module.ts | 8 +- src/app/modules/recipes/recipes.module.ts | 11 +- src/app/modules/recipes/recipes.sass | 12 + src/app/modules/recipes/recipes.ts | 3 + .../components/action-bar/action-bar.html | 2 +- .../components/action-bar/action-bar.ts | 6 +- .../shared/components/forms/buttons.ts | 17 ++ .../shared/components/forms/forms.module.ts | 30 ++- .../modules/shared/components/forms/forms.ts | 13 +- .../components/forms/submit-button.html | 1 + .../shared/components/inputs/input.html | 4 +- .../shared/components/inputs/inputs.ts | 22 +- .../shared/components/inputs/select.html | 17 +- .../modules/shared/model/material.model.ts | 24 +- .../modules/touch-up-kit/components/form.ts | 4 +- 26 files changed, 383 insertions(+), 296 deletions(-) rename src/app/modules/recipes/{pages/explore/explore.component.html => explore.html} (100%) rename src/app/modules/recipes/{pages/explore/explore.component.ts => explore.ts} (83%) rename src/app/modules/recipes/{pages/list/list.component.html => list.html} (83%) rename src/app/modules/recipes/{pages/list/list.component.ts => list.ts} (68%) delete mode 100644 src/app/modules/recipes/pages/explore/explore.component.sass delete mode 100644 src/app/modules/recipes/pages/list/list.component.sass create mode 100644 src/app/modules/shared/components/forms/buttons.ts create mode 100644 src/app/modules/shared/components/forms/submit-button.html diff --git a/docker-compose.yml b/docker-compose.yml index 11391cd..0defb89 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,12 +8,12 @@ services: MYSQL_ROOT_PASSWORD: "pass" MYSQL_DATABASE: "cre" ports: - - "3306:3306" + - "3307:3306" backend: image: registry.fyloz.dev:5443/colorrecipesexplorer/backend:latest environment: spring_profiles_active: "mysql,debug" - cre_database_url: "mysql://database:3306/cre" + cre_database_url: "mysql://database:3307/cre" cre_database_username: "root" cre_database_password: "pass" CRE_ENABLE_DB_UPDATE: 1 diff --git a/src/app/modules/recipes/add.html b/src/app/modules/recipes/add.html index 185e14a..aa827e1 100644 --- a/src/app/modules/recipes/add.html +++ b/src/app/modules/recipes/add.html @@ -1 +1,10 @@ - + + + Retour + + + + + + + diff --git a/src/app/modules/recipes/components/mix-editor/mix-editor.component.html b/src/app/modules/recipes/components/mix-editor/mix-editor.component.html index a89926b..0e9faf0 100644 --- a/src/app/modules/recipes/components/mix-editor/mix-editor.component.html +++ b/src/app/modules/recipes/components/mix-editor/mix-editor.component.html @@ -1,132 +1,122 @@ - - - Création d'un mélange pour la recette {{recipe.company.name}} - - {{recipe.name}} - Modification du mélange {{mix.mixType.name}} de la - recette {{recipe.company.name}} - {{recipe.name}} - - - - Nom - - - - - Type de produit - - - {{materialType.name}} - - - + + + + Retour + + + Supprimer + Enregistrer + + -
- -
-
- - - - - -
+ + Ajouter un mélange à la couleur {{recipe.company.name}} + - {{recipe.name}} + Modification du mélange {{mix.mixType.name}} de la + couleur {{recipe.company.name}} + - {{recipe.name}} - - - - - - + + + + + + - - - + +
Position - {{mixMaterial.position}} - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + - - - - + + + + - - -
Position + {{mixMaterial.position}} + + + + + + Produit + + + + + + + + + + + + + + + Quantité + + + + Unités + + +

%

-
Produit - - - - {{materialDisplayName(material)}} - - - - Quantité - - - - Unités - - -

%

+ + + {{units}} - - - {{units}} - - - - + + -
- - - - - - + + + + + +
- +
@ViewChild('deleteConfirmBox') deleteConfirmBox: ConfirmBoxComponent + @ViewChild(CreForm) creForm: ICreForm @Input() mixId: number | null @Input() recipeId: number | null @@ -36,35 +40,36 @@ export class MixEditorComponent extends ErrorHandlingComponent { @Output() save = new EventEmitter() + recipe: Recipe mix: Mix | null - recipe: Recipe | null - materialTypes$ = this.materialTypeService.all - form: FormGroup - nameControl: FormControl - materialTypeControl: FormControl - - mixMaterials: MixMaterialDto[] = [] editionMode = false units = UNIT_MILLILITER hoveredMixMaterial: MixMaterial | null - columns = ['position', 'buttonsPosition', 'material', 'quantity', 'units', 'buttonRemove'] + tableColumns = ['position', 'buttonsPosition', 'material', 'quantity', 'units', 'buttonRemove'] deleting = false errorHandlers = [{ filter: error => error.type === 'notfound-mix-id', - consumer: error => this.urlUtils.navigateTo('/color/list') + consumer: _ => this.urlUtils.navigateTo('/color/list') }, { filter: error => error.type === 'exists-material-name', messageProducer: error => `Un produit avec le nom '${error.name}' existe déjà` }, { filter: error => error.type === 'cannotdelete-mix', - messageProducer: error => 'Ce mélange est utilisé par un ou plusieurs autres mélanges' + messageProducer: _ => 'Ce mélange est utilisé par un ou plusieurs autres mélanges' }, { filter: error => error.type === 'invalid-mixmaterial-first', - messageProducer: error => 'La quantité du premier ingrédient du mélange ne peut pas être exprimée en pourcentage' + messageProducer: _ => 'La quantité du premier ingrédient du mélange ne peut pas être exprimée en pourcentage' }] + controls: any + materialTypeEntries$ = this.materialTypeService.all.pipe( + map(materialTypes => materialTypes.map(materialType => new CreInputEntry(materialType.id, materialType.name))), + ) + + private _mixMaterials: MixMaterialDto[] = [] + constructor( private mixService: MixService, private recipeService: RecipeService, @@ -87,22 +92,42 @@ export class MixEditorComponent extends ErrorHandlingComponent { this.editionMode = true } - this.subscribeEntityById( - this.recipeService, - this.recipeId, - r => { - this.recipe = r + this.fetchRecipe() + this.fetchMaterials() + } + + private fetchRecipe() { + this.subscribe( + this.recipeService.getById(this.recipeId), + recipe => { + this.recipe = recipe + if (this.editionMode) { - this.mix = this.recipe.mixes.find(m => m.id === this.mixId) + this.mix = this.recipe.mixes.find(mix => mix.id === this.mixId) this.mixMaterials = mixMaterialsAsMixMaterialsDto(this.mix) } else { this.addBlankMixMaterial() } - this.generateForm() + + this.createControls() } ) } + private fetchMaterials() { + this.subscribe( + this.materialService.all, + materials => this.materials = materials + ) + } + + private createControls() { + this.controls = { + name: new FormControl(this.mix?.mixType.name, Validators.required), + materialType: new FormControl(this.mix?.mixType.material.materialType.id, Validators.required) + } + } + addRow() { this.addBlankMixMaterial() this.mixTable.renderRows() @@ -141,9 +166,9 @@ export class MixEditorComponent extends ErrorHandlingComponent { submit() { this.save.emit({ - name: this.nameControl.value, + name: this.controls.name.value, recipeId: this.recipeId, - materialTypeId: this.materialTypeControl.value, + materialTypeId: this.controls.materialType.value, mixMaterials: this.mixMaterials, units: this.units }) @@ -154,8 +179,21 @@ export class MixEditorComponent extends ErrorHandlingComponent { this.subscribeAndNavigate(this.mixService.delete(this.mixId), `/color/edit/${this.recipeId}`) } - getAvailableMaterials(mixMaterial: MixMaterialDto): Material[] { - return this.materials.filter(m => mixMaterial.materialId === m.id || this.mixMaterials.filter(mm => mm.materialId === m.id).length === 0) + getAvailableMaterials(mixMaterial: MixMaterialDto): CreInputEntry[] { + // return this.materialService.all.pipe( + // map(materials => materials.filter(material => { + // return mixMaterial.materialId === material.id || this.mixMaterials.filter(mm => mm.materialId === material.id).length === 0 + // })), + // map(materials => this.sortedMaterials(materials)), + // map(materials => materials.map(material => new CreInputEntry(material.id, material.name))) + // ) + console.log(this.materials.map(material => new CreInputEntry(material.id, material.name))) + return [] + // return this.materials.map(material => new CreInputEntry(material.id, material.name)) + // return this.materials + // .filter(m => mixMaterial.materialId === m.id || this.mixMaterials.filter(mm => mm.materialId === m.id).length === 0) + // .sort(materialComparator) + // .map(material => new CreInputEntry(material.id, material.name)) } materialDisplayName(material: Material): string { @@ -165,43 +203,18 @@ export class MixEditorComponent extends ErrorHandlingComponent { return material.name } - sortedMaterials(materials: Material[]): Material[] { - return materials.sort((a, b) => { - const aPrefixName = a.materialType.prefix.toLowerCase() - const bPrefixName = b.materialType.prefix.toLowerCase() - - if (aPrefixName < bPrefixName) { - return -1 - } else if (aPrefixName > bPrefixName) { - return 1 - } else { - const aName = a.name.toLowerCase() - const bName = b.name.toLowerCase() - - if (aName < bName) { - return -1 - } else if (aName > bName) { - return 1 - } else { - return 0 - } - } - }) + get mixMaterials(): MixMaterialDto[] { + return this._mixMaterials } - private generateForm() { - this.nameControl = new FormControl(this.mix ? this.mix.mixType.name : null, Validators.required) - this.materialTypeControl = new FormControl(this.mix ? this.mix.mixType.material.materialType.id : null, Validators.required) - this.form = this.formBuilder.group({ - name: this.nameControl, - materialType: this.materialTypeControl - }) + set mixMaterials(mixMaterials: MixMaterialDto[]) { + this._mixMaterials = mixMaterials + this.mixTable.renderRows() } private addBlankMixMaterial() { - this.mixMaterials.push( - new MixMaterialDto(null, 0, false, this.mixMaterials.length + 1) - ) + const mixMaterial = new MixMaterialDto(null, 0, false, this.mixMaterials.length + 1) + this.mixMaterials = [...this.mixMaterials, mixMaterial] } private updateMixMaterialPosition(mixMaterial: MixMaterialDto, updatedPosition: number) { diff --git a/src/app/modules/recipes/pages/explore/explore.component.html b/src/app/modules/recipes/explore.html similarity index 100% rename from src/app/modules/recipes/pages/explore/explore.component.html rename to src/app/modules/recipes/explore.html diff --git a/src/app/modules/recipes/pages/explore/explore.component.ts b/src/app/modules/recipes/explore.ts similarity index 83% rename from src/app/modules/recipes/pages/explore/explore.component.ts rename to src/app/modules/recipes/explore.ts index 3a184a5..084693e 100644 --- a/src/app/modules/recipes/pages/explore/explore.component.ts +++ b/src/app/modules/recipes/explore.ts @@ -1,34 +1,34 @@ import {Component} from '@angular/core' -import {RecipeService} from '../../services/recipe.service' +import {RecipeService} from './services/recipe.service' import {ActivatedRoute, Router} from '@angular/router' -import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' +import {ErrorHandlingComponent} from '../shared/components/subscribing.component' import { MixMaterialDto, Recipe, recipeMixCount, recipeNoteForGroupId, recipeStepCount -} from '../../../shared/model/recipe.model' +} from '../shared/model/recipe.model' import {Observable, Subject} from 'rxjs' -import {ErrorHandler, 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' -import {AccountService} from '../../../accounts/services/account.service' -import {Permission} from '../../../shared/model/user' +import {ErrorHandler, 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' +import {AccountService} from '../accounts/services/account.service' +import {Permission} from '../shared/model/user' import {FormControl} from '@angular/forms'; -import {map, tap} from 'rxjs/operators'; -import {CreInputEntry} from '../../../shared/components/inputs/inputs'; +import {map} from 'rxjs/operators'; +import {CreInputEntry} from '../shared/components/inputs/inputs'; @Component({ - selector: 'cre-explore', - templateUrl: './explore.component.html', - styleUrls: ['./explore.component.sass'] + selector: 'cre-recipe-explore', + templateUrl: './explore.html', + styleUrls: ['./recipes.sass'] }) -export class ExploreComponent extends ErrorHandlingComponent { +export class CreRecipeExplore extends ErrorHandlingComponent { deductErrorBody = {} units$ = new Subject() selectedGroupId: number | null diff --git a/src/app/modules/recipes/form.html b/src/app/modules/recipes/form.html index 7f72041..3dc9805 100644 --- a/src/app/modules/recipes/form.html +++ b/src/app/modules/recipes/form.html @@ -5,7 +5,7 @@
- + Ajouter une couleur Modifier la couleur {{recipe.name}} @@ -18,8 +18,4 @@ - - Retour - Enregistrer - diff --git a/src/app/modules/recipes/pages/list/list.component.html b/src/app/modules/recipes/list.html similarity index 83% rename from src/app/modules/recipes/pages/list/list.component.html rename to src/app/modules/recipes/list.html index d06df5d..4ad8ce1 100644 --- a/src/app/modules/recipes/pages/list/list.component.html +++ b/src/app/modules/recipes/list.html @@ -1,31 +1,19 @@ -
- - Recherche - - - -
- -
-
+ + + + + + Ajouter + +

Il n'y a actuellement aucune bannière enregistrée dans le système.

-

Vous pouvez en créer une ici.

+

Vous pouvez en créer une ici. +

- +

Il n'y a actuellement aucune recette enregistrée dans le système.

Vous pouvez en créer une ici.

diff --git a/src/app/modules/recipes/pages/list/list.component.ts b/src/app/modules/recipes/list.ts similarity index 68% rename from src/app/modules/recipes/pages/list/list.component.ts rename to src/app/modules/recipes/list.ts index 53077a6..051212f 100644 --- a/src/app/modules/recipes/pages/list/list.component.ts +++ b/src/app/modules/recipes/list.ts @@ -1,23 +1,24 @@ -import {ChangeDetectorRef, Component} from '@angular/core' -import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' -import {RecipeService} from '../../services/recipe.service' -import {Permission} from '../../../shared/model/user' -import {AccountService} from '../../../accounts/services/account.service' -import {getRecipeLuma, Recipe} from '../../../shared/model/recipe.model' -import {ActivatedRoute, Router} from '@angular/router' -import {ErrorService} from '../../../shared/service/error.service' -import {AppState} from '../../../shared/app-state' -import {ConfigService} from '../../../shared/service/config.service' -import {Company} from '../../../shared/model/company.model'; -import {CompanyService} from '../../../company/service/company.service'; -import {Config} from '../../../shared/model/config.model'; +import {ChangeDetectorRef, Component} from '@angular/core'; +import {ErrorHandlingComponent} from '../shared/components/subscribing.component'; +import {Company} from '../shared/model/company.model'; +import {getRecipeLuma, Recipe} from '../shared/model/recipe.model'; +import {CompanyService} from '../company/service/company.service'; +import {RecipeService} from './services/recipe.service'; +import {AccountService} from '../accounts/services/account.service'; +import {ConfigService} from '../shared/service/config.service'; +import {AppState} from '../shared/app-state'; +import {ErrorService} from '../shared/service/error.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {Config} from '../shared/model/config.model'; +import {Permission} from '../shared/model/user'; +import {FormControl} from '@angular/forms'; @Component({ - selector: 'cre-list', - templateUrl: './list.component.html', - styleUrls: ['./list.component.sass'] + selector: 'cre-recipe-list', + templateUrl: 'list.html', + styleUrls: ['recipes.sass'] }) -export class ListComponent extends ErrorHandlingComponent { +export class RecipeList extends ErrorHandlingComponent { companies: Company[] = [] recipes: Map = new Map() tableCols = ['name', 'description', 'color', 'sample', 'iconNotApproved', 'buttonView', 'buttonEdit'] @@ -25,6 +26,8 @@ export class ListComponent extends ErrorHandlingComponent { panelForcedExpanded = false hiddenRecipes = [] + searchControl: FormControl + constructor( private companyService: CompanyService, private recipeService: RecipeService, @@ -47,7 +50,7 @@ export class ListComponent extends ErrorHandlingComponent { this.subscribe( this.configService.get(Config.EMERGENCY_MODE), config => { - if (config.content == "true") { + if (config.content == 'true') { this.urlUtils.navigateTo('/admin/config/') } } @@ -55,6 +58,12 @@ export class ListComponent extends ErrorHandlingComponent { this.fetchCompanies() this.fetchRecipes() + + this.searchControl = new FormControl('') + this.subscribe( + this.searchControl.valueChanges, + value => this.searchRecipes(value) + ) } private fetchCompanies() { @@ -72,7 +81,8 @@ export class ListComponent extends ErrorHandlingComponent { ) } - searchRecipes() { + searchRecipes(searchQuery) { + this.searchQuery = searchQuery if (this.searchQuery.length > 0 && !this.panelForcedExpanded) { this.panelForcedExpanded = true this.cdRef.detectChanges() diff --git a/src/app/modules/recipes/pages/explore/explore.component.sass b/src/app/modules/recipes/pages/explore/explore.component.sass deleted file mode 100644 index 1775c49..0000000 --- a/src/app/modules/recipes/pages/explore/explore.component.sass +++ /dev/null @@ -1,2 +0,0 @@ -.recipe-content > div - margin: 0 3rem 3rem diff --git a/src/app/modules/recipes/pages/list/list.component.sass b/src/app/modules/recipes/pages/list/list.component.sass deleted file mode 100644 index e5fb34c..0000000 --- a/src/app/modules/recipes/pages/list/list.component.sass +++ /dev/null @@ -1,9 +0,0 @@ -mat-expansion-panel - width: 60rem - margin: 20px auto - -.button-add - margin-top: .8rem - -.recipe-color-circle - box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 0 rgba(0, 0, 0, 0.12) diff --git a/src/app/modules/recipes/recipes-routing.module.ts b/src/app/modules/recipes/recipes-routing.module.ts index 95fd2a9..f258782 100644 --- a/src/app/modules/recipes/recipes-routing.module.ts +++ b/src/app/modules/recipes/recipes-routing.module.ts @@ -1,14 +1,14 @@ import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; -import {ListComponent} from './pages/list/list.component'; -import {ExploreComponent} from './pages/explore/explore.component'; +import {CreRecipeExplore} from './explore'; import {MixEditComponent} from './pages/mix/mix-edit/mix-edit.component'; import {MixAddComponent} from './pages/mix/mix-add/mix-add.component'; import {RecipeAdd, RecipeEdit} from './recipes'; +import {RecipeList} from './list'; const routes: Routes = [{ path: 'list', - component: ListComponent + component: RecipeList }, { path: 'add', component: RecipeAdd @@ -23,7 +23,7 @@ const routes: Routes = [{ component: MixEditComponent }, { path: 'explore/:id', - component: ExploreComponent + component: CreRecipeExplore }, { path: '', pathMatch: 'full', diff --git a/src/app/modules/recipes/recipes.module.ts b/src/app/modules/recipes/recipes.module.ts index 71aacfe..3ba16c2 100644 --- a/src/app/modules/recipes/recipes.module.ts +++ b/src/app/modules/recipes/recipes.module.ts @@ -2,10 +2,9 @@ import {NgModule} from '@angular/core' import {RecipesRoutingModule} from './recipes-routing.module' import {SharedModule} from '../shared/shared.module' -import {ListComponent} from './pages/list/list.component' import {MatExpansionModule} from '@angular/material/expansion' import {FormsModule} from '@angular/forms' -import {ExploreComponent} from './pages/explore/explore.component' +import {CreRecipeExplore} from './explore' import {RecipeInfoComponent} from './components/recipe-info/recipe-info.component' import {MixTableComponent} from './components/mix-table/mix-table.component' import {StepListComponent} from './components/step-list/step-list.component' @@ -21,12 +20,11 @@ import {CreInputsModule} from '../shared/components/inputs/inputs.module'; import {CreButtonsModule} from '../shared/components/buttons/buttons.module'; import {RecipeAdd, RecipeEdit, RecipeForm} from './recipes'; import {CreActionBarModule} from '../shared/components/action-bar/action-bar.module'; - +import {RecipeList} from './list'; @NgModule({ declarations: [ - ListComponent, - ExploreComponent, + CreRecipeExplore, RecipeInfoComponent, MixTableComponent, StepListComponent, @@ -39,7 +37,8 @@ import {CreActionBarModule} from '../shared/components/action-bar/action-bar.mod MixesCardComponent, RecipeForm, RecipeAdd, - RecipeEdit + RecipeEdit, + RecipeList ], exports: [ UnitSelectorComponent diff --git a/src/app/modules/recipes/recipes.sass b/src/app/modules/recipes/recipes.sass index d19072a..353d3df 100644 --- a/src/app/modules/recipes/recipes.sass +++ b/src/app/modules/recipes/recipes.sass @@ -4,3 +4,15 @@ cre-form margin-top: 0 !important +mat-expansion-panel + width: 60rem + margin: 20px auto + +.button-add + margin-top: .8rem + +.recipe-color-circle + box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 0 rgba(0, 0, 0, 0.12) + +.recipe-content > div + margin: 0 3rem 3rem diff --git a/src/app/modules/recipes/recipes.ts b/src/app/modules/recipes/recipes.ts index 1be6565..fed6fe8 100644 --- a/src/app/modules/recipes/recipes.ts +++ b/src/app/modules/recipes/recipes.ts @@ -16,6 +16,7 @@ import {AlertService} from '../shared/service/alert.service'; import {GroupService} from '../groups/services/group.service'; import {StepTableComponent} from './components/step-table/step-table.component'; import {anyMap} from '../shared/utils/map.utils'; +import {CreForm, ICreForm} from '../shared/components/forms/forms'; @Component({ selector: 'recipe-form', @@ -26,6 +27,8 @@ import {anyMap} from '../shared/utils/map.utils'; export class RecipeForm extends SubscribingComponent { @Input() recipe: Recipe | null + @ViewChild(CreForm) creForm: ICreForm + @Output() submitForm = new EventEmitter(); controls: any diff --git a/src/app/modules/shared/components/action-bar/action-bar.html b/src/app/modules/shared/components/action-bar/action-bar.html index 4bad334..6aa7ad0 100644 --- a/src/app/modules/shared/components/action-bar/action-bar.html +++ b/src/app/modules/shared/components/action-bar/action-bar.html @@ -1,3 +1,3 @@ -
+
diff --git a/src/app/modules/shared/components/action-bar/action-bar.ts b/src/app/modules/shared/components/action-bar/action-bar.ts index 506bed9..61df16b 100644 --- a/src/app/modules/shared/components/action-bar/action-bar.ts +++ b/src/app/modules/shared/components/action-bar/action-bar.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core' +import {Component, Input} from '@angular/core' @Component({ selector: 'cre-action-group', @@ -11,4 +11,6 @@ export class CreActionGroup {} selector: 'cre-action-bar', templateUrl: 'action-bar.html' }) -export class CreActionBar {} +export class CreActionBar { + @Input() reverse = false +} diff --git a/src/app/modules/shared/components/forms/buttons.ts b/src/app/modules/shared/components/forms/buttons.ts new file mode 100644 index 0000000..0cebdc4 --- /dev/null +++ b/src/app/modules/shared/components/forms/buttons.ts @@ -0,0 +1,17 @@ +import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {ICreForm} from './forms'; + +@Component({ + selector: 'cre-submit-button', + templateUrl: 'submit-button.html' +}) +export class CreSubmitButton { + @Input() form: ICreForm + @Input() valid: boolean | null + + @Output() submit = new EventEmitter() + + get disableButton(): boolean { + return !this.form || !(this.valid ?? this.form.valid) + } +} diff --git a/src/app/modules/shared/components/forms/forms.module.ts b/src/app/modules/shared/components/forms/forms.module.ts index 2ee4a91..4e1a91c 100644 --- a/src/app/modules/shared/components/forms/forms.module.ts +++ b/src/app/modules/shared/components/forms/forms.module.ts @@ -1,28 +1,34 @@ import {NgModule} from '@angular/core' -import {CreFormActions, CreFormComponent, CreFormContent, CreFormTitle} from './forms' +import {CreFormActions, CreForm, CreFormContent, CreFormTitle} from './forms' import {MatCardModule} from '@angular/material/card' import {CommonModule} from '@angular/common' import {MatButtonModule} from '@angular/material/button' import {ReactiveFormsModule} from '@angular/forms' +import {CreSubmitButton} from './buttons'; +import {CreButtonsModule} from '../buttons/buttons.module'; @NgModule({ declarations: [ - CreFormComponent, + CreForm, CreFormTitle, CreFormContent, - CreFormActions + CreFormActions, + CreSubmitButton ], exports: [ - CreFormComponent, + CreForm, CreFormTitle, CreFormContent, - CreFormActions + CreFormActions, + CreSubmitButton ], - imports: [ - MatCardModule, - CommonModule, - MatButtonModule, - ReactiveFormsModule - ] + imports: [ + MatCardModule, + CommonModule, + MatButtonModule, + ReactiveFormsModule, + CreButtonsModule + ] }) -export class CreFormsModule {} +export class CreFormsModule { +} diff --git a/src/app/modules/shared/components/forms/forms.ts b/src/app/modules/shared/components/forms/forms.ts index 98a556c..7619f15 100644 --- a/src/app/modules/shared/components/forms/forms.ts +++ b/src/app/modules/shared/components/forms/forms.ts @@ -1,6 +1,12 @@ import {Component, ContentChild, Directive, Input, OnInit, ViewEncapsulation} from '@angular/core' import {FormBuilder, FormGroup} from '@angular/forms' +export interface ICreForm { + form: FormGroup + valid: boolean + invalid: boolean +} + @Directive({ selector: 'cre-form-title' }) @@ -17,7 +23,6 @@ export class CreFormContent { selector: 'cre-form-actions' }) export class CreFormActions { - } @Component({ @@ -26,7 +31,7 @@ export class CreFormActions { styleUrls: ['forms.sass'], encapsulation: ViewEncapsulation.None }) -export class CreFormComponent implements OnInit { +export class CreForm implements ICreForm, OnInit { @ContentChild(CreFormActions) formActions: CreFormActions @Input() formControls: { [key: string]: any } @@ -45,6 +50,10 @@ export class CreFormComponent implements OnInit { return !!this.formActions } + get valid(): boolean { + return this.form && this.form.valid + } + get invalid(): boolean { return !this.form || this.form.invalid } diff --git a/src/app/modules/shared/components/forms/submit-button.html b/src/app/modules/shared/components/forms/submit-button.html new file mode 100644 index 0000000..8e9289a --- /dev/null +++ b/src/app/modules/shared/components/forms/submit-button.html @@ -0,0 +1 @@ +Enregistrer diff --git a/src/app/modules/shared/components/inputs/input.html b/src/app/modules/shared/components/inputs/input.html index 7b5f60f..f58c818 100644 --- a/src/app/modules/shared/components/inputs/input.html +++ b/src/app/modules/shared/components/inputs/input.html @@ -5,7 +5,7 @@ @@ -14,7 +14,7 @@ diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts index fb038e9..74335cf 100644 --- a/src/app/modules/shared/components/inputs/inputs.ts +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -15,7 +15,7 @@ import { } from '@angular/core' import {AbstractControl, FormControl, ValidationErrors, ValidatorFn, Validators} from '@angular/forms' import {COMMA, ENTER} from '@angular/cdk/keycodes' -import {Observable, Subject} from 'rxjs' +import {isObservable, Observable, Subject} from 'rxjs' import {map, takeUntil} from 'rxjs/operators' import {MatChipInputEvent} from '@angular/material/chips' import {MatAutocomplete, MatAutocompleteSelectedEvent} from '@angular/material/autocomplete' @@ -50,16 +50,16 @@ export class CreInputComponent extends _CreInputBase implements AfterViewInit { @ViewChild('input') input: any @ContentChild(TemplateRef) errors: TemplateRef + fieldRequired = true + ngAfterViewInit() { const element = this.input.nativeElement element.type = this.type element.step = this.step.toString() element.placeholder = this.placeholder element.autocomplete = this.autocomplete ? 'on' : 'off' - } - get isFieldRequired(): boolean { - return this.control ? this.control.validator && this.control.validator({} as AbstractControl)?.required : this.required + this.fieldRequired = this.control ? this.control.validator && this.control.validator({} as AbstractControl)?.required : this.required } } @@ -400,7 +400,19 @@ export class CreSliderInputComponent { templateUrl: 'select.html' }) export class CreSelectComponent extends _CreInputBase { - @Input() entries: Observable + @Input() entries: Observable | CreInputEntry[] + + get entriesAreObservable(): boolean { + return isObservable(this.entries) + } + + get arrayEntries(): CreInputEntry[] { + return this.entries as CreInputEntry[] + } + + get observableEntries(): Observable { + return this.entries as Observable + } } export class CreInputEntry { diff --git a/src/app/modules/shared/components/inputs/select.html b/src/app/modules/shared/components/inputs/select.html index 6fd806b..e17b4a4 100644 --- a/src/app/modules/shared/components/inputs/select.html +++ b/src/app/modules/shared/components/inputs/select.html @@ -1,8 +1,17 @@ {{label}} - - - {{entry.display || entry.value}} - + + + + {{entry.display || entry.value}} + + + + + {{entry.display || entry.value}} + + diff --git a/src/app/modules/shared/model/material.model.ts b/src/app/modules/shared/model/material.model.ts index 56187fd..5c31599 100644 --- a/src/app/modules/shared/model/material.model.ts +++ b/src/app/modules/shared/model/material.model.ts @@ -1,4 +1,4 @@ -import {MaterialType} from "./materialtype.model"; +import {MaterialType} from './materialtype.model'; import {openPdf} from '../utils/utils' export class Material { @@ -15,3 +15,25 @@ export class Material { export function openSimdut(material: Material) { openPdf(material.simdutUrl) } + +export const materialComparator = (a: Material, b: Material): number => { + const aPrefixName = a.materialType.prefix.toLowerCase() + const bPrefixName = b.materialType.prefix.toLowerCase() + + if (aPrefixName < bPrefixName) { + return -1 + } else if (aPrefixName > bPrefixName) { + return 1 + } else { + const aName = a.name.toLowerCase() + const bName = b.name.toLowerCase() + + if (aName < bName) { + return -1 + } else if (aName > bName) { + return 1 + } else { + return 0 + } + } +} diff --git a/src/app/modules/touch-up-kit/components/form.ts b/src/app/modules/touch-up-kit/components/form.ts index 09c7248..5fa1a89 100644 --- a/src/app/modules/touch-up-kit/components/form.ts +++ b/src/app/modules/touch-up-kit/components/form.ts @@ -1,6 +1,6 @@ import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core' import {chipListRequired, CreInputEntry, CreChipComboBoxComponent} from '../../shared/components/inputs/inputs' -import {CreFormComponent} from '../../shared/components/forms/forms' +import {CreForm} from '../../shared/components/forms/forms' import {TouchUpKitProductEditor} from './product-editor' import {FormControl, Validators} from '@angular/forms' import {RecipeService} from '../../recipes/services/recipe.service' @@ -18,7 +18,7 @@ import {map} from 'rxjs/operators' export class TouchUpKitForm extends SubscribingComponent { @ViewChild('finishInput') finishInput: CreChipComboBoxComponent @ViewChild('materialInput') materialInput: CreChipComboBoxComponent - @ViewChild(CreFormComponent) form: CreFormComponent + @ViewChild(CreForm) form: CreForm @ViewChild(TouchUpKitProductEditor) contentEditor: TouchUpKitProductEditor @Input() touchUpKit: TouchUpKit | null From a1baa334ed224c0b9c20699038e77bdfe03547b2 Mon Sep 17 00:00:00 2001 From: William Date: Wed, 10 Nov 2021 17:25:32 -0500 Subject: [PATCH 08/28] Fix all fields are forced required --- src/app/modules/shared/components/inputs/inputs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts index 74335cf..a9e105f 100644 --- a/src/app/modules/shared/components/inputs/inputs.ts +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -50,7 +50,7 @@ export class CreInputComponent extends _CreInputBase implements AfterViewInit { @ViewChild('input') input: any @ContentChild(TemplateRef) errors: TemplateRef - fieldRequired = true + fieldRequired = false ngAfterViewInit() { const element = this.input.nativeElement From cb51e66d119cfb1e553e1de67ee7eba5f316be6e Mon Sep 17 00:00:00 2001 From: William Date: Mon, 15 Nov 2021 21:52:17 -0500 Subject: [PATCH 09/28] Broken --- .../mix-editor/mix-editor.component.html | 10 ++-- .../mix-editor/mix-editor.component.ts | 55 ++++++------------- .../pages/mix/mix-add/mix-add.component.html | 3 +- .../pages/mix/mix-add/mix-add.component.ts | 22 +++++++- .../mix/mix-edit/mix-edit.component.html | 2 +- .../pages/mix/mix-edit/mix-edit.component.ts | 24 ++++++-- .../shared/components/inputs/inputs.ts | 8 ++- 7 files changed, 71 insertions(+), 53 deletions(-) diff --git a/src/app/modules/recipes/components/mix-editor/mix-editor.component.html b/src/app/modules/recipes/components/mix-editor/mix-editor.component.html index 0e9faf0..f9081ac 100644 --- a/src/app/modules/recipes/components/mix-editor/mix-editor.component.html +++ b/src/app/modules/recipes/components/mix-editor/mix-editor.component.html @@ -1,7 +1,7 @@ - + - Retour + Retour Supprimer @@ -18,8 +18,8 @@ - + + @@ -71,7 +71,7 @@ - + diff --git a/src/app/modules/recipes/components/mix-editor/mix-editor.component.ts b/src/app/modules/recipes/components/mix-editor/mix-editor.component.ts index 325729c..d795617 100644 --- a/src/app/modules/recipes/components/mix-editor/mix-editor.component.ts +++ b/src/app/modules/recipes/components/mix-editor/mix-editor.component.ts @@ -20,7 +20,7 @@ import {ActivatedRoute, Router} from '@angular/router' import {ConfirmBoxComponent} from '../../../shared/components/confirm-box/confirm-box.component' import {AccountService} from '../../../accounts/services/account.service' import {ErrorService} from '../../../shared/service/error.service' -import {map, tap} from 'rxjs/operators'; +import {map} from 'rxjs/operators'; import {CreInputEntry} from '../../../shared/components/inputs/inputs'; import {CreForm, ICreForm} from '../../../shared/components/forms/forms'; @@ -30,19 +30,17 @@ import {CreForm, ICreForm} from '../../../shared/components/forms/forms'; styleUrls: ['./mix-editor.component.sass'] }) export class MixEditorComponent extends ErrorHandlingComponent { - @ViewChild('matTable') mixTable: MatTable + @ViewChild(MatTable, {static: true}) mixTable: MatTable @ViewChild('deleteConfirmBox') deleteConfirmBox: ConfirmBoxComponent @ViewChild(CreForm) creForm: ICreForm @Input() mixId: number | null - @Input() recipeId: number | null - @Input() materials: Material[] + @Input() recipe: Recipe + @Input() mix: Mix | null + @Input() materials: Material[] = [] @Output() save = new EventEmitter() - recipe: Recipe - mix: Mix | null - editionMode = false units = UNIT_MILLILITER hoveredMixMaterial: MixMaterial | null @@ -92,33 +90,14 @@ export class MixEditorComponent extends ErrorHandlingComponent { this.editionMode = true } - this.fetchRecipe() - this.fetchMaterials() - } + if (this.editionMode) { + this.mix = this.recipe.mixes.find(mix => mix.id === this.mixId) + this.mixMaterials = mixMaterialsAsMixMaterialsDto(this.mix) + } else { + this.addBlankMixMaterial() + } - private fetchRecipe() { - this.subscribe( - this.recipeService.getById(this.recipeId), - recipe => { - this.recipe = recipe - - if (this.editionMode) { - this.mix = this.recipe.mixes.find(mix => mix.id === this.mixId) - this.mixMaterials = mixMaterialsAsMixMaterialsDto(this.mix) - } else { - this.addBlankMixMaterial() - } - - this.createControls() - } - ) - } - - private fetchMaterials() { - this.subscribe( - this.materialService.all, - materials => this.materials = materials - ) + this.createControls() } private createControls() { @@ -167,7 +146,7 @@ export class MixEditorComponent extends ErrorHandlingComponent { submit() { this.save.emit({ name: this.controls.name.value, - recipeId: this.recipeId, + recipeId: this.recipe.id, materialTypeId: this.controls.materialType.value, mixMaterials: this.mixMaterials, units: this.units @@ -176,7 +155,7 @@ export class MixEditorComponent extends ErrorHandlingComponent { delete() { this.deleting = true - this.subscribeAndNavigate(this.mixService.delete(this.mixId), `/color/edit/${this.recipeId}`) + this.subscribeAndNavigate(this.mixService.delete(this.mixId), `/color/edit/${this.recipe.id}`) } getAvailableMaterials(mixMaterial: MixMaterialDto): CreInputEntry[] { @@ -187,8 +166,10 @@ export class MixEditorComponent extends ErrorHandlingComponent { // map(materials => this.sortedMaterials(materials)), // map(materials => materials.map(material => new CreInputEntry(material.id, material.name))) // ) - console.log(this.materials.map(material => new CreInputEntry(material.id, material.name))) - return [] + return this.materials + .filter(m => mixMaterial.materialId === m.id || this.mixMaterials.filter(mm => mm.materialId === m.id).length === 0) + .sort(materialComparator) + .map(material => new CreInputEntry(material.id, material.name)) // return this.materials.map(material => new CreInputEntry(material.id, material.name)) // return this.materials // .filter(m => mixMaterial.materialId === m.id || this.mixMaterials.filter(mm => mm.materialId === m.id).length === 0) diff --git a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html index 128e7d2..0b94ba5 100644 --- a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html +++ b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html @@ -1,5 +1,6 @@ diff --git a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts index 0cae5af..258319e 100644 --- a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts +++ b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts @@ -5,6 +5,8 @@ import {ActivatedRoute, Router} from '@angular/router' import {ErrorHandlingComponent} from '../../../../shared/components/subscribing.component' import {MixService} from '../../../services/mix.service' import {ErrorService} from '../../../../shared/service/error.service' +import {Recipe} from "../../../../shared/model/recipe.model"; +import {RecipeService} from "../../../services/recipe.service"; @Component({ selector: 'cre-mix-add', @@ -12,10 +14,13 @@ import {ErrorService} from '../../../../shared/service/error.service' styleUrls: ['./mix-add.component.sass'] }) export class MixAddComponent extends ErrorHandlingComponent { - recipeId: number | null - materials: Material[] | null + materials: Material[] | null = [new Material(0, "Example", 1000, null, null)] + recipe: Recipe | null + + private recipeId: number | null constructor( + private recipeService: RecipeService, private materialService: MaterialService, private mixService: MixService, errorService: ErrorService, @@ -29,10 +34,21 @@ export class MixAddComponent extends ErrorHandlingComponent { super.ngOnInit() this.recipeId = this.urlUtils.parseIntUrlParam('recipeId') + this.fetchRecipe() + // this.fetchMaterials() + } + private fetchRecipe() { + this.subscribe( + this.recipeService.getById(this.recipeId), + recipe => this.recipe = recipe + ) + } + + private fetchMaterials() { this.subscribe( this.materialService.getAllForMixCreation(this.recipeId), - m => this.materials = m + materials => this.materials = materials ) } diff --git a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html index 762bae6..8133e72 100644 --- a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html +++ b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html @@ -1,6 +1,6 @@ diff --git a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts index 5b360fd..1ab2a1b 100644 --- a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts +++ b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts @@ -4,9 +4,10 @@ import {ErrorHandlingComponent} from '../../../../shared/components/subscribing. import {Material} from '../../../../shared/model/material.model' import {MaterialService} from '../../../../material/service/material.service' import {MixService} from '../../../services/mix.service' -import {ErrorHandlerComponent, ErrorService} from '../../../../shared/service/error.service' -import {MixMaterialDto} from '../../../../shared/model/recipe.model' +import {ErrorService} from '../../../../shared/service/error.service' +import {MixMaterialDto, Recipe} from '../../../../shared/model/recipe.model' import {AlertService} from '../../../../shared/service/alert.service' +import {RecipeService} from "../../../services/recipe.service"; @Component({ selector: 'cre-mix-edit', @@ -15,10 +16,13 @@ import {AlertService} from '../../../../shared/service/alert.service' }) export class MixEditComponent extends ErrorHandlingComponent { mixId: number | null - recipeId: number | null + recipe: Recipe | null materials: Material[] | null + private recipeId: number | null + constructor( + private recipeService: RecipeService, private materialService: MaterialService, private mixService: MixService, private alertService: AlertService, @@ -35,9 +39,21 @@ export class MixEditComponent extends ErrorHandlingComponent { this.mixId = this.urlUtils.parseIntUrlParam('id') this.recipeId = this.urlUtils.parseIntUrlParam('recipeId') + this.fetchRecipe() + this.fetchMaterials() + } + + private fetchRecipe() { + this.subscribe( + this.recipeService.getById(this.recipeId), + recipe => this.recipe = recipe + ) + } + + private fetchMaterials() { this.subscribe( this.materialService.getAllForMixUpdate(this.mixId), - m => this.materials = m + materials => this.materials = materials ) } diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts index a9e105f..dd74af5 100644 --- a/src/app/modules/shared/components/inputs/inputs.ts +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -399,8 +399,12 @@ export class CreSliderInputComponent { selector: 'cre-select', templateUrl: 'select.html' }) -export class CreSelectComponent extends _CreInputBase { - @Input() entries: Observable | CreInputEntry[] +export class CreSelectComponent extends _CreInputBase implements AfterViewInit { + @Input() entries: CreInputEntry[] | Observable + + ngAfterViewInit(): void { + console.log(this.entries) + } get entriesAreObservable(): boolean { return isObservable(this.entries) From c3122c2e3e9659ae362e1f18ed364f99054c6e01 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 16 Nov 2021 19:58:52 -0500 Subject: [PATCH 10/28] Start rewriting mix editor --- .../mix-editor/mix-editor.component.html | 2 +- src/app/modules/recipes/mix/add.html | 6 + src/app/modules/recipes/mix/form.html | 8 + src/app/modules/recipes/mix/info-form.html | 10 ++ .../modules/recipes/mix/materials-form.html | 44 +++++ src/app/modules/recipes/mix/materials-form.ts | 162 ++++++++++++++++++ src/app/modules/recipes/mix/mix.ts | 105 ++++++++++++ .../modules/recipes/recipes-routing.module.ts | 3 +- src/app/modules/recipes/recipes.module.ts | 12 +- .../shared/components/inputs/combo-box.html | 4 +- .../shared/components/inputs/inputs.ts | 63 ++++--- .../components/tables/position-buttons.html | 17 ++ .../shared/components/tables/tables.module.ts | 12 +- .../shared/components/tables/tables.ts | 31 +++- 14 files changed, 447 insertions(+), 32 deletions(-) create mode 100644 src/app/modules/recipes/mix/add.html create mode 100644 src/app/modules/recipes/mix/form.html create mode 100644 src/app/modules/recipes/mix/info-form.html create mode 100644 src/app/modules/recipes/mix/materials-form.html create mode 100644 src/app/modules/recipes/mix/materials-form.ts create mode 100644 src/app/modules/recipes/mix/mix.ts create mode 100644 src/app/modules/shared/components/tables/position-buttons.html diff --git a/src/app/modules/recipes/components/mix-editor/mix-editor.component.html b/src/app/modules/recipes/components/mix-editor/mix-editor.component.html index f9081ac..5e294cd 100644 --- a/src/app/modules/recipes/components/mix-editor/mix-editor.component.html +++ b/src/app/modules/recipes/components/mix-editor/mix-editor.component.html @@ -71,7 +71,7 @@ - + diff --git a/src/app/modules/recipes/mix/add.html b/src/app/modules/recipes/mix/add.html new file mode 100644 index 0000000..43a2dc3 --- /dev/null +++ b/src/app/modules/recipes/mix/add.html @@ -0,0 +1,6 @@ + + diff --git a/src/app/modules/recipes/mix/form.html b/src/app/modules/recipes/mix/form.html new file mode 100644 index 0000000..0dd72c3 --- /dev/null +++ b/src/app/modules/recipes/mix/form.html @@ -0,0 +1,8 @@ + + + + + diff --git a/src/app/modules/recipes/mix/info-form.html b/src/app/modules/recipes/mix/info-form.html new file mode 100644 index 0000000..915b4e1 --- /dev/null +++ b/src/app/modules/recipes/mix/info-form.html @@ -0,0 +1,10 @@ + + + Ajouter un mélange à la couleur {{recipe.company.name}} - {{recipe.name}} + + + + + + + diff --git a/src/app/modules/recipes/mix/materials-form.html b/src/app/modules/recipes/mix/materials-form.html new file mode 100644 index 0000000..49baca8 --- /dev/null +++ b/src/app/modules/recipes/mix/materials-form.html @@ -0,0 +1,44 @@ + + + Position + {{mixMaterial.position + 1}} + + + + + + + + + + + + Produit + + + + + + + + Quantité + + + + + + + + Ajouter + + + Retirer + + + diff --git a/src/app/modules/recipes/mix/materials-form.ts b/src/app/modules/recipes/mix/materials-form.ts new file mode 100644 index 0000000..762bff8 --- /dev/null +++ b/src/app/modules/recipes/mix/materials-form.ts @@ -0,0 +1,162 @@ +import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, ViewChild} from "@angular/core"; +import {CreTable} from "../../shared/components/tables/tables"; +import {MixMaterialDto, sortMixMaterialsDto} from "../../shared/model/recipe.model"; +import {Observable, Subject} from "rxjs"; +import {Material} from "../../shared/model/material.model"; +import {FormControl, Validators} from "@angular/forms"; +import {takeUntil} from "rxjs/operators"; +import {CreInputEntry} from "../../shared/components/inputs/inputs"; + +@Component({ + selector: 'cre-mix-materials-form', + templateUrl: 'materials-form.html' +}) +export class MixMaterialsForm implements AfterViewInit, OnDestroy { + @ViewChild(CreTable) table: CreTable + + @Input() materials: Observable + + mixMaterials: MixMaterialDto[] = [] + columns = ['position', 'positionButtons', 'material', 'quantity', 'endButton'] + + private _allMaterials: Material[] + private _controls: ControlsByPosition[] = [] + private _availableMaterialsEntries: MaterialEntriesByPosition[] = [] + private _destroy$ = new Subject() + + constructor( + private cdRef: ChangeDetectorRef + ) { + } + + ngAfterViewInit() { + this.materials.subscribe({ + next: materials => { + this._allMaterials = materials + + this.addRow() + this.cdRef.detectChanges() + } + }) + } + + ngOnDestroy() { + this._destroy$.next(true) + this._destroy$.complete() + } + + addRow() { + const position = this.nextPosition; + const mixMaterial = new MixMaterialDto(0, 0, false, position); + + const materialIdControl = new FormControl(null, Validators.required) + const quantityControl = new FormControl(null, Validators.required) + + materialIdControl.valueChanges + .pipe(takeUntil(this._destroy$)) + .subscribe({ + next: materialId => { + this.mixMaterials.filter(x => x.materialId === mixMaterial.materialId)[0].materialId = materialId + this.refreshAvailableMaterials() + } + }) + + this._controls.push({ + position, + controls: { + materialId: materialIdControl, + quantity: quantityControl + } + }) + this._availableMaterialsEntries.push({ + position, + entries: this.filterMaterials(mixMaterial) + }) + this.mixMaterials.push(mixMaterial) + this.table.renderRows() + } + + removeRow(mixMaterial: MixMaterialDto) { + this.mixMaterials = this.mixMaterials.filter(x => x.position != mixMaterial.position) + + for (let position = mixMaterial.position + 1; position < this.mixMaterials.length; position++) { + this.updatePosition(this.getMixMaterialByPosition(position), position - 1, false) + } + } + + updatePosition(mixMaterial: MixMaterialDto, newPosition: number, switchPositions = true) { + const currentPosition = mixMaterial.position + + this.getControlsByPosition(currentPosition).position = newPosition + this.getMaterialEntriesByPosition(currentPosition).position = newPosition + + if (switchPositions) { + this.updatePosition(this.getMixMaterialByPosition(newPosition), currentPosition, false) + } + + mixMaterial.position = newPosition + this.sortTable() + } + + getControls(position: number): MixMaterialControls { + return this.getControlsByPosition(position).controls + } + + getAvailableMaterialEntries(position: number): CreInputEntry[] { + return this.getMaterialEntriesByPosition(position).entries + } + + get materialCount(): number { + return this._allMaterials ? this._allMaterials.length : 0; + } + + private get nextPosition(): number { + return this.mixMaterials.length + } + + private getMixMaterialByPosition(position: number): MixMaterialDto { + return this.mixMaterials.filter(x => x.position === position)[0] + } + + private getControlsByPosition(position: number): ControlsByPosition { + return this._controls.filter(control => control.position === position)[0] + } + + private getMaterialEntriesByPosition(position: number): MaterialEntriesByPosition { + return this._availableMaterialsEntries.filter(control => control.position === position)[0] + } + + private refreshAvailableMaterials() { + this.mixMaterials + .sort((a, b) => a.position - b.position) + .forEach(mixMaterial => { + this.getMaterialEntriesByPosition(mixMaterial.position).entries = this.filterMaterials(mixMaterial) + }) + } + + private sortTable() { + this.mixMaterials = sortMixMaterialsDto(this.mixMaterials) + this.table.renderRows() + } + + private filterMaterials(mixMaterial: MixMaterialDto): CreInputEntry[] { + return this._allMaterials + .filter(material => mixMaterial.materialId === material.id || this.mixMaterials.filter(mm => mm.materialId === material.id).length === 0) + .map(material => new CreInputEntry(material.id, material.name)) + } +} + +interface MixMaterialControls { + materialId: FormControl + quantity: FormControl +} + +interface ControlsByPosition { + position: number + controls: MixMaterialControls +} + +interface MaterialEntriesByPosition { + position: number + entries: CreInputEntry[] +} diff --git a/src/app/modules/recipes/mix/mix.ts b/src/app/modules/recipes/mix/mix.ts new file mode 100644 index 0000000..7bdb95b --- /dev/null +++ b/src/app/modules/recipes/mix/mix.ts @@ -0,0 +1,105 @@ +import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild} from "@angular/core"; +import {SubscribingComponent} from "../../shared/components/subscribing.component"; +import {MixMaterialDto, Recipe, sortMixMaterialsDto} from "../../shared/model/recipe.model"; +import {ErrorService} from "../../shared/service/error.service"; +import {ActivatedRoute, Router} from "@angular/router"; +import {RecipeService} from "../services/recipe.service"; +import {FormControl, Validators} from "@angular/forms"; +import {Observable, Subject} from "rxjs"; +import {MaterialType} from "../../shared/model/materialtype.model"; +import {MaterialTypeService} from "../../material-type/service/material-type.service"; +import {CreInputEntry} from "../../shared/components/inputs/inputs"; +import {filter, map, takeUntil, tap} from "rxjs/operators"; +import {Material} from "../../shared/model/material.model"; +import {MaterialService} from "../../material/service/material.service"; +import {CreTable} from "../../shared/components/tables/tables"; +import {MatTable} from "@angular/material/table"; + +@Component({ + selector: 'cre-mix-add', + templateUrl: 'add.html' +}) +export class MixAdd extends SubscribingComponent { + materialTypes$ = this.materialTypeService.all + materials$: Observable + + private _recipe: Recipe | null + + constructor( + private recipeService: RecipeService, + private materialTypeService: MaterialTypeService, + private materialService: MaterialService, + errorService: ErrorService, + router: Router, + activatedRoute: ActivatedRoute + ) { + super(errorService, activatedRoute, router) + } + + ngOnInit() { + this.fetchRecipe() + } + + private fetchRecipe() { + const recipeId = this.urlUtils.parseIntUrlParam('recipeId') + + this.subscribe( + this.recipeService.getById(recipeId), + recipe => this.recipe = recipe + ) + } + + set recipe(recipe: Recipe) { + this._recipe = recipe; + this.materials$ = this.materialService.getAllForMixCreation(recipe.id) + } + + get recipe(): Recipe { + return this._recipe; + } +} + +@Component({ + selector: 'cre-mix-form', + templateUrl: 'form.html' +}) +export class MixForm { + @Input() recipe: Recipe + @Input() materialTypes: Observable + @Input() materials: Observable +} + +@Component({ + selector: 'cre-mix-info-form', + templateUrl: 'info-form.html' +}) +export class MixInfoForm implements OnInit { + @Input() recipe: Recipe + @Input() materialTypes: Observable + + materialTypeEntries: Observable + controls: any + + ngOnInit() { + this.materialTypeEntries = this.materialTypes.pipe( + map(materialTypes => { + return materialTypes.map(materialType => new CreInputEntry(materialType.id, materialType.name)) + }) + ) + + this.controls = { + name: new FormControl(null, Validators.required), + materialType: new FormControl(null, Validators.required) + } + } + + get mixName(): string { + return this.controls.name.value + } + + get mixMaterialTypeId(): number { + return this.controls.materialType.value + } +} + + diff --git a/src/app/modules/recipes/recipes-routing.module.ts b/src/app/modules/recipes/recipes-routing.module.ts index f258782..75657d8 100644 --- a/src/app/modules/recipes/recipes-routing.module.ts +++ b/src/app/modules/recipes/recipes-routing.module.ts @@ -5,6 +5,7 @@ import {MixEditComponent} from './pages/mix/mix-edit/mix-edit.component'; import {MixAddComponent} from './pages/mix/mix-add/mix-add.component'; import {RecipeAdd, RecipeEdit} from './recipes'; import {RecipeList} from './list'; +import {MixAdd} from "./mix/mix"; const routes: Routes = [{ path: 'list', @@ -17,7 +18,7 @@ const routes: Routes = [{ component: RecipeEdit }, { path: 'add/mix/:recipeId', - component: MixAddComponent + component: MixAdd }, { path: 'edit/mix/:recipeId/:id', component: MixEditComponent diff --git a/src/app/modules/recipes/recipes.module.ts b/src/app/modules/recipes/recipes.module.ts index 3ba16c2..2579711 100644 --- a/src/app/modules/recipes/recipes.module.ts +++ b/src/app/modules/recipes/recipes.module.ts @@ -21,6 +21,9 @@ import {CreButtonsModule} from '../shared/components/buttons/buttons.module'; import {RecipeAdd, RecipeEdit, RecipeForm} from './recipes'; import {CreActionBarModule} from '../shared/components/action-bar/action-bar.module'; import {RecipeList} from './list'; +import {MixAdd, MixForm, MixInfoForm} from "./mix/mix"; +import {CreTablesModule} from "../shared/components/tables/tables.module"; +import {MixMaterialsForm} from "./mix/materials-form"; @NgModule({ declarations: [ @@ -38,7 +41,11 @@ import {RecipeList} from './list'; RecipeForm, RecipeAdd, RecipeEdit, - RecipeList + RecipeList, + MixAdd, + MixForm, + MixInfoForm, + MixMaterialsForm ], exports: [ UnitSelectorComponent @@ -51,7 +58,8 @@ import {RecipeList} from './list'; MatSortModule, CreInputsModule, CreButtonsModule, - CreActionBarModule + CreActionBarModule, + CreTablesModule ] }) export class RecipesModule { diff --git a/src/app/modules/shared/components/inputs/combo-box.html b/src/app/modules/shared/components/inputs/combo-box.html index 7df0d9f..96decd8 100644 --- a/src/app/modules/shared/components/inputs/combo-box.html +++ b/src/app/modules/shared/components/inputs/combo-box.html @@ -16,8 +16,8 @@ - - {{entry.display || entry.value}} + + {{entry.value}} diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts index dd74af5..0e7811f 100644 --- a/src/app/modules/shared/components/inputs/inputs.ts +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -1,5 +1,5 @@ import { - AfterViewInit, + AfterViewInit, ChangeDetectorRef, Component, ContentChild, Directive, @@ -52,6 +52,12 @@ export class CreInputComponent extends _CreInputBase implements AfterViewInit { fieldRequired = false + constructor( + private cdRef: ChangeDetectorRef + ) { + super(); + } + ngAfterViewInit() { const element = this.input.nativeElement element.type = this.type @@ -60,6 +66,8 @@ export class CreInputComponent extends _CreInputBase implements AfterViewInit { element.autocomplete = this.autocomplete ? 'on' : 'off' this.fieldRequired = this.control ? this.control.validator && this.control.validator({} as AbstractControl)?.required : this.required + + this.cdRef.detectChanges() } } @@ -148,12 +156,11 @@ export class CreChipInputComponent implements OnInit { templateUrl: 'combo-box.html', encapsulation: ViewEncapsulation.None }) -export class CreComboBoxComponent implements OnInit { +export class CreComboBoxComponent { @Input() control: AbstractControl @Input() label: string @Input() icon: string @Input() required = true - @Input() entries: Observable @ContentChild(TemplateRef) errors: TemplateRef @@ -162,22 +169,38 @@ export class CreComboBoxComponent implements OnInit { private _destroy$ = new Subject(); private _entries: CreInputEntry[] + private _controlsInitialized = false - ngOnInit() { - this.entries.pipe(takeUntil(this._destroy$)) - .subscribe({ - next: entries => { - this._entries = entries - - if (this.control.value) { - this.internalControl.setValue(this.findEntryByKey(this.control.value)?.value) + @Input() + set entries(entries: Observable | CreInputEntry[]) { + if (isObservable(this.entries)) { + (entries as Observable).pipe(takeUntil(this._destroy$)) + .subscribe({ + next: entries => { + this._entries = entries } + }) + } else { + this._entries = (entries as CreInputEntry[]) + } - if (this.control.disabled) { - this.internalControl.disable() - } - } - }) + this.initControls() + } + + getEntries(): CreInputEntry[] { + return this._entries + } + + private initControls() { + if (this._controlsInitialized) return + + if (this.control.value) { + this.internalControl.setValue(this.findEntryByKey(this.control.value)?.value) + } + + if (this.control.disabled) { + this.internalControl.disable() + } this.internalControl = new FormControl({ value: null, @@ -193,6 +216,8 @@ export class CreComboBoxComponent implements OnInit { } } }) + + this._controlsInitialized = true } private findEntryByKey(key: any): CreInputEntry | null { @@ -399,13 +424,9 @@ export class CreSliderInputComponent { selector: 'cre-select', templateUrl: 'select.html' }) -export class CreSelectComponent extends _CreInputBase implements AfterViewInit { +export class CreSelectComponent extends _CreInputBase { @Input() entries: CreInputEntry[] | Observable - ngAfterViewInit(): void { - console.log(this.entries) - } - get entriesAreObservable(): boolean { return isObservable(this.entries) } diff --git a/src/app/modules/shared/components/tables/position-buttons.html b/src/app/modules/shared/components/tables/position-buttons.html new file mode 100644 index 0000000..cb85502 --- /dev/null +++ b/src/app/modules/shared/components/tables/position-buttons.html @@ -0,0 +1,17 @@ + + + + diff --git a/src/app/modules/shared/components/tables/tables.module.ts b/src/app/modules/shared/components/tables/tables.module.ts index 2e9576d..1b67ca8 100644 --- a/src/app/modules/shared/components/tables/tables.module.ts +++ b/src/app/modules/shared/components/tables/tables.module.ts @@ -1,20 +1,26 @@ import {NgModule} from '@angular/core' import {MatTableModule} from '@angular/material/table' import {CommonModule} from '@angular/common' -import {CreInteractiveCell, CreTable} from './tables' +import {CreInteractiveCell, CrePositionButtons, CreTable} from './tables' +import {MatButtonModule} from "@angular/material/button"; +import {MatIconModule} from "@angular/material/icon"; @NgModule({ declarations: [ CreTable, - CreInteractiveCell + CreInteractiveCell, + CrePositionButtons ], imports: [ MatTableModule, - CommonModule + CommonModule, + MatButtonModule, + MatIconModule ], exports: [ CreTable, CreInteractiveCell, + CrePositionButtons ] }) export class CreTablesModule { diff --git a/src/app/modules/shared/components/tables/tables.ts b/src/app/modules/shared/components/tables/tables.ts index 59cec5c..b98a7a3 100644 --- a/src/app/modules/shared/components/tables/tables.ts +++ b/src/app/modules/shared/components/tables/tables.ts @@ -2,9 +2,9 @@ import { AfterContentInit, Component, ContentChildren, - Directive, + Directive, EventEmitter, HostBinding, - Input, + Input, Output, QueryList, ViewChild, ViewEncapsulation @@ -80,4 +80,31 @@ export class CreTable implements AfterContentInit { this.interactiveCells.forEach(cell => cell.selectedIndex = index) } } + + renderRows() { + this.table.renderRows() + } +} + +@Component({ + selector: 'cre-table-position-buttons', + templateUrl: 'position-buttons.html' +}) +export class CrePositionButtons { + @Input() position = 0 + @Input() min = 0 + @Input() max: number + @Input() hidden = false + + @Output() positionChange = new EventEmitter(); + + increasePosition() { + this.position += 1; + this.positionChange.emit(this.position) + } + + decreasePosition() { + this.position -= 1; + this.positionChange.emit(this.position) + } } From 971e3dcb3c487a10c0046c2213cccae6f1ff3be4 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 17 Nov 2021 19:23:13 -0500 Subject: [PATCH 11/28] Working mix editor --- docker-compose.yml | 2 +- .../unit-selector.component.html | 2 +- .../unit-selector/unit-selector.component.ts | 15 ++- src/app/modules/recipes/mix/add.html | 23 +++- .../modules/recipes/mix/materials-form.html | 106 +++++++++++------- src/app/modules/recipes/mix/materials-form.ts | 82 ++++++++++---- src/app/modules/recipes/mix/mix.ts | 67 ++++++----- src/app/modules/recipes/recipes.ts | 4 +- .../shared/components/inputs/combo-box.html | 6 +- .../shared/components/inputs/inputs.ts | 47 +++++--- 10 files changed, 237 insertions(+), 117 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0defb89..333e1ea 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: image: registry.fyloz.dev:5443/colorrecipesexplorer/backend:latest environment: spring_profiles_active: "mysql,debug" - cre_database_url: "mysql://database:3307/cre" + cre_database_url: "mysql://database/cre" cre_database_username: "root" cre_database_password: "pass" CRE_ENABLE_DB_UPDATE: 1 diff --git a/src/app/modules/recipes/components/unit-selector/unit-selector.component.html b/src/app/modules/recipes/components/unit-selector/unit-selector.component.html index 4b82721..b00e879 100644 --- a/src/app/modules/recipes/components/unit-selector/unit-selector.component.html +++ b/src/app/modules/recipes/components/unit-selector/unit-selector.component.html @@ -1,6 +1,6 @@ Unités - + Millilitres Litres diff --git a/src/app/modules/recipes/components/unit-selector/unit-selector.component.ts b/src/app/modules/recipes/components/unit-selector/unit-selector.component.ts index 418677f..9f8d192 100644 --- a/src/app/modules/recipes/components/unit-selector/unit-selector.component.ts +++ b/src/app/modules/recipes/components/unit-selector/unit-selector.component.ts @@ -1,17 +1,28 @@ -import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core' import {UNIT_GALLON, UNIT_LITER, UNIT_MILLILITER} from "../../../shared/units"; +import {FormControl} from '@angular/forms' @Component({ selector: 'cre-unit-selector', templateUrl: './unit-selector.component.html', styleUrls: ['./unit-selector.component.sass'] }) -export class UnitSelectorComponent { +export class UnitSelectorComponent implements OnInit { readonly unitConstants = {UNIT_MILLILITER, UNIT_LITER, UNIT_GALLON} @Input() unit = UNIT_MILLILITER @Input() showLabel = true @Input() short = false + @Input() control: FormControl | null @Output() unitChange = new EventEmitter() + + ngOnInit() { + this.control?.setValue(this.unit) + } + + onUnitChange(newUnit: string) { + this.control?.setValue(newUnit) + this.unitChange.emit(newUnit) + } } diff --git a/src/app/modules/recipes/mix/add.html b/src/app/modules/recipes/mix/add.html index 43a2dc3..26639dd 100644 --- a/src/app/modules/recipes/mix/add.html +++ b/src/app/modules/recipes/mix/add.html @@ -1,6 +1,17 @@ - - + + + + Retour + + + Enregistrer + + + + + + diff --git a/src/app/modules/recipes/mix/materials-form.html b/src/app/modules/recipes/mix/materials-form.html index 49baca8..91d95ca 100644 --- a/src/app/modules/recipes/mix/materials-form.html +++ b/src/app/modules/recipes/mix/materials-form.html @@ -1,44 +1,70 @@ - - - Position - {{mixMaterial.position + 1}} - +
+ +

Il n'y a actuellement aucun produit enregistré dans le système.

+

Vous pouvez en créer un ici. +

+
- - - - - - - + + + Position + {{mixMaterial.position + 1}} + - - Produit - - - - - + + + + + + + - - Quantité - - - - + + Produit + + + + + - - - Ajouter - - - Retirer - - - + + Quantité + + + + + + + Unités + + + + + + % + + + + + + + Ajouter + + + + Retirer + + + + +
diff --git a/src/app/modules/recipes/mix/materials-form.ts b/src/app/modules/recipes/mix/materials-form.ts index 762bff8..7ecc05c 100644 --- a/src/app/modules/recipes/mix/materials-form.ts +++ b/src/app/modules/recipes/mix/materials-form.ts @@ -1,11 +1,13 @@ -import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, ViewChild} from "@angular/core"; -import {CreTable} from "../../shared/components/tables/tables"; -import {MixMaterialDto, sortMixMaterialsDto} from "../../shared/model/recipe.model"; -import {Observable, Subject} from "rxjs"; -import {Material} from "../../shared/model/material.model"; -import {FormControl, Validators} from "@angular/forms"; -import {takeUntil} from "rxjs/operators"; -import {CreInputEntry} from "../../shared/components/inputs/inputs"; +import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, ViewChild, ViewChildren} from '@angular/core' +import {CreTable} from '../../shared/components/tables/tables' +import {MixMaterialDto, sortMixMaterialsDto} from '../../shared/model/recipe.model' +import {Observable, Subject} from 'rxjs' +import {Material, materialComparator} from '../../shared/model/material.model' +import {FormControl, Validators} from '@angular/forms' +import {takeUntil} from 'rxjs/operators' +import {CreComboBoxComponent, CreInputEntry} from '../../shared/components/inputs/inputs' +import {AccountService} from '../../accounts/services/account.service' +import {Permission} from '../../shared/model/user' @Component({ selector: 'cre-mix-materials-form', @@ -13,11 +15,12 @@ import {CreInputEntry} from "../../shared/components/inputs/inputs"; }) export class MixMaterialsForm implements AfterViewInit, OnDestroy { @ViewChild(CreTable) table: CreTable + @ViewChildren(CreComboBoxComponent) materialComboBoxes: CreComboBoxComponent[] @Input() materials: Observable + @Input() mixMaterials: MixMaterialDto[] = [] - mixMaterials: MixMaterialDto[] = [] - columns = ['position', 'positionButtons', 'material', 'quantity', 'endButton'] + columns = ['position', 'positionButtons', 'material', 'quantity', 'units', 'endButton'] private _allMaterials: Material[] private _controls: ControlsByPosition[] = [] @@ -25,6 +28,7 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { private _destroy$ = new Subject() constructor( + private accountService: AccountService, private cdRef: ChangeDetectorRef ) { } @@ -46,18 +50,21 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { } addRow() { - const position = this.nextPosition; - const mixMaterial = new MixMaterialDto(0, 0, false, position); + const position = this.nextPosition + const mixMaterial = new MixMaterialDto(null, 0, false, position) const materialIdControl = new FormControl(null, Validators.required) - const quantityControl = new FormControl(null, Validators.required) + const quantityControl = new FormControl(0, Validators.required) + const unitsControl = new FormControl(null, Validators.required) materialIdControl.valueChanges .pipe(takeUntil(this._destroy$)) .subscribe({ next: materialId => { - this.mixMaterials.filter(x => x.materialId === mixMaterial.materialId)[0].materialId = materialId + mixMaterial.materialId = materialId this.refreshAvailableMaterials() + this.cdRef.detectChanges() + this.materialComboBoxes.forEach(comboBox => comboBox.reloadEntries()) } }) @@ -65,7 +72,8 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { position, controls: { materialId: materialIdControl, - quantity: quantityControl + quantity: quantityControl, + units: unitsControl } }) this._availableMaterialsEntries.push({ @@ -86,15 +94,18 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { updatePosition(mixMaterial: MixMaterialDto, newPosition: number, switchPositions = true) { const currentPosition = mixMaterial.position + const currentControls = this.getControlsByPosition(currentPosition) + const currentMaterialEntries = this.getMaterialEntriesByPosition(currentPosition) - this.getControlsByPosition(currentPosition).position = newPosition - this.getMaterialEntriesByPosition(currentPosition).position = newPosition - + // Update before current to prevent position conflicts if (switchPositions) { this.updatePosition(this.getMixMaterialByPosition(newPosition), currentPosition, false) } mixMaterial.position = newPosition + currentControls.position = newPosition + currentMaterialEntries.position = newPosition + this.sortTable() } @@ -106,8 +117,24 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { return this.getMaterialEntriesByPosition(position).entries } + areUnitsPercents(mixMaterial: MixMaterialDto): boolean { + return mixMaterial.materialId ? this._allMaterials.filter(x => x.id === mixMaterial.materialId)[0].materialType.usePercentages : false + } + + get hasMaterialEditPermission(): boolean { + return this.accountService.hasPermission(Permission.EDIT_MATERIALS) + } + get materialCount(): number { - return this._allMaterials ? this._allMaterials.length : 0; + return this._allMaterials ? this._allMaterials.length : 0 + } + + get valid(): boolean { + return this._controls + .map(controls => controls.controls) + .map(controls => [controls.materialId, controls.quantity]) + .flatMap(controls => controls) + .every(control => control.valid) } private get nextPosition(): number { @@ -141,14 +168,27 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { private filterMaterials(mixMaterial: MixMaterialDto): CreInputEntry[] { return this._allMaterials - .filter(material => mixMaterial.materialId === material.id || this.mixMaterials.filter(mm => mm.materialId === material.id).length === 0) - .map(material => new CreInputEntry(material.id, material.name)) + .filter(material => { + // Prevent use of percents in first position + if (material.materialType.usePercentages && mixMaterial.position === 0) { + return false + } + + if (mixMaterial.materialId === material.id) { + return true + } + + return this.mixMaterials.filter(x => x.materialId === material.id).length <= 0 + }) + .sort(materialComparator) + .map(material => new CreInputEntry(material.id, material.name, material.materialType.prefix ? `[${material.materialType.prefix}] ${material.name}` : material.name)) } } interface MixMaterialControls { materialId: FormControl quantity: FormControl + units: FormControl } interface ControlsByPosition { diff --git a/src/app/modules/recipes/mix/mix.ts b/src/app/modules/recipes/mix/mix.ts index 7bdb95b..35ccc73 100644 --- a/src/app/modules/recipes/mix/mix.ts +++ b/src/app/modules/recipes/mix/mix.ts @@ -1,19 +1,19 @@ -import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild} from "@angular/core"; -import {SubscribingComponent} from "../../shared/components/subscribing.component"; -import {MixMaterialDto, Recipe, sortMixMaterialsDto} from "../../shared/model/recipe.model"; -import {ErrorService} from "../../shared/service/error.service"; -import {ActivatedRoute, Router} from "@angular/router"; -import {RecipeService} from "../services/recipe.service"; -import {FormControl, Validators} from "@angular/forms"; -import {Observable, Subject} from "rxjs"; -import {MaterialType} from "../../shared/model/materialtype.model"; -import {MaterialTypeService} from "../../material-type/service/material-type.service"; -import {CreInputEntry} from "../../shared/components/inputs/inputs"; -import {filter, map, takeUntil, tap} from "rxjs/operators"; -import {Material} from "../../shared/model/material.model"; -import {MaterialService} from "../../material/service/material.service"; -import {CreTable} from "../../shared/components/tables/tables"; -import {MatTable} from "@angular/material/table"; +import {Component, Input, OnInit, ViewChild} from '@angular/core' +import {SubscribingComponent} from '../../shared/components/subscribing.component' +import {Recipe} from '../../shared/model/recipe.model' +import {ErrorService} from '../../shared/service/error.service' +import {ActivatedRoute, Router} from '@angular/router' +import {RecipeService} from '../services/recipe.service' +import {FormControl, Validators} from '@angular/forms' +import {Observable} from 'rxjs' +import {MaterialType} from '../../shared/model/materialtype.model' +import {MaterialTypeService} from '../../material-type/service/material-type.service' +import {CreInputEntry} from '../../shared/components/inputs/inputs' +import {map} from 'rxjs/operators' +import {Material} from '../../shared/model/material.model' +import {MaterialService} from '../../material/service/material.service' +import {CreForm} from '../../shared/components/forms/forms' +import {MixMaterialsForm} from './materials-form' @Component({ selector: 'cre-mix-add', @@ -50,30 +50,22 @@ export class MixAdd extends SubscribingComponent { } set recipe(recipe: Recipe) { - this._recipe = recipe; + this._recipe = recipe this.materials$ = this.materialService.getAllForMixCreation(recipe.id) } get recipe(): Recipe { - return this._recipe; + return this._recipe } } -@Component({ - selector: 'cre-mix-form', - templateUrl: 'form.html' -}) -export class MixForm { - @Input() recipe: Recipe - @Input() materialTypes: Observable - @Input() materials: Observable -} - @Component({ selector: 'cre-mix-info-form', templateUrl: 'info-form.html' }) export class MixInfoForm implements OnInit { + @ViewChild(CreForm) form: CreForm + @Input() recipe: Recipe @Input() materialTypes: Observable @@ -100,6 +92,25 @@ export class MixInfoForm implements OnInit { get mixMaterialTypeId(): number { return this.controls.materialType.value } + + get valid(): boolean { + return this.form.valid + } } +@Component({ + selector: 'cre-mix-form', + templateUrl: 'form.html' +}) +export class MixForm { + @ViewChild(MixInfoForm) infoForm: MixInfoForm + @ViewChild(MixMaterialsForm) mixMaterialsForm: MixMaterialsForm + @Input() recipe: Recipe + @Input() materialTypes: Observable + @Input() materials: Observable + + get valid(): boolean { + return this.infoForm?.valid && this.mixMaterialsForm?.valid + } +} diff --git a/src/app/modules/recipes/recipes.ts b/src/app/modules/recipes/recipes.ts index fed6fe8..bdc619e 100644 --- a/src/app/modules/recipes/recipes.ts +++ b/src/app/modules/recipes/recipes.ts @@ -25,10 +25,10 @@ import {CreForm, ICreForm} from '../shared/components/forms/forms'; encapsulation: ViewEncapsulation.None }) export class RecipeForm extends SubscribingComponent { - @Input() recipe: Recipe | null - @ViewChild(CreForm) creForm: ICreForm + @Input() recipe: Recipe | null + @Output() submitForm = new EventEmitter(); controls: any diff --git a/src/app/modules/shared/components/inputs/combo-box.html b/src/app/modules/shared/components/inputs/combo-box.html index 96decd8..67e0162 100644 --- a/src/app/modules/shared/components/inputs/combo-box.html +++ b/src/app/modules/shared/components/inputs/combo-box.html @@ -1,4 +1,4 @@ - + {{label}} - - {{entry.value}} + + {{entry.display ? entry.display : entry.value}} diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts index 0e7811f..df922cd 100644 --- a/src/app/modules/shared/components/inputs/inputs.ts +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -16,7 +16,7 @@ import { import {AbstractControl, FormControl, ValidationErrors, ValidatorFn, Validators} from '@angular/forms' import {COMMA, ENTER} from '@angular/cdk/keycodes' import {isObservable, Observable, Subject} from 'rxjs' -import {map, takeUntil} from 'rxjs/operators' +import {map, startWith, takeUntil} from 'rxjs/operators' import {MatChipInputEvent} from '@angular/material/chips' import {MatAutocomplete, MatAutocompleteSelectedEvent} from '@angular/material/autocomplete' @@ -55,7 +55,7 @@ export class CreInputComponent extends _CreInputBase implements AfterViewInit { constructor( private cdRef: ChangeDetectorRef ) { - super(); + super() } ngAfterViewInit() { @@ -165,34 +165,36 @@ export class CreComboBoxComponent { @ContentChild(TemplateRef) errors: TemplateRef internalControl: FormControl + filteredEntries: CreInputEntry[] validValue = false - private _destroy$ = new Subject(); + private _destroy$ = new Subject() private _entries: CreInputEntry[] private _controlsInitialized = false @Input() set entries(entries: Observable | CreInputEntry[]) { - if (isObservable(this.entries)) { + if (isObservable(entries)) { (entries as Observable).pipe(takeUntil(this._destroy$)) .subscribe({ next: entries => { - this._entries = entries + this.initControls(entries) } }) } else { - this._entries = (entries as CreInputEntry[]) + this.initControls((entries as CreInputEntry[])) } - - this.initControls() } - getEntries(): CreInputEntry[] { - return this._entries + reloadEntries() { + this.filteredEntries = this.filterEntries(this.internalControl.value) } - private initControls() { - if (this._controlsInitialized) return + private initControls(entries) { + this._entries = entries + if (this._controlsInitialized) { + return + } if (this.control.value) { this.internalControl.setValue(this.findEntryByKey(this.control.value)?.value) @@ -206,7 +208,8 @@ export class CreComboBoxComponent { value: null, disabled: false }, Validators.compose([this.control.validator, this.valueValidator()])) - this.internalControl.valueChanges.pipe(takeUntil(this._destroy$)) + this.internalControl.valueChanges + .pipe(takeUntil(this._destroy$)) .subscribe({ next: value => { if (this.internalControl.valid) { @@ -214,12 +217,30 @@ export class CreComboBoxComponent { } else { this.control.setValue(null) } + + this.filteredEntries = this.filterEntries(value) } }) + this.reloadEntries() this._controlsInitialized = true } + private filterEntries(value: string): CreInputEntry[] { + if (!value) { + return this._entries + } + + const valueLowerCase = value.toLowerCase() + return this._entries.filter(entry => { + if (entry.display) { + return entry.display.toLowerCase().includes(valueLowerCase) + } else { + return entry.value.toLowerCase().includes(valueLowerCase) + } + }) + } + private findEntryByKey(key: any): CreInputEntry | null { const found = this._entries.filter(e => e.key === key) if (found.length <= 0) { From 6a5f74016f7c47413d44a8c934d5cdb5428bdf1d Mon Sep 17 00:00:00 2001 From: William Date: Wed, 17 Nov 2021 21:30:03 -0500 Subject: [PATCH 12/28] Only some bugs to fix --- .../mix-editor/mix-editor.component.html | 126 ----------- .../mix-editor/mix-editor.component.sass | 6 - .../mix-editor/mix-editor.component.ts | 214 ------------------ .../mix-table/mix-table.component.ts | 5 +- src/app/modules/recipes/mix/add.html | 4 +- .../modules/recipes/mix/materials-form.html | 8 +- src/app/modules/recipes/mix/materials-form.ts | 49 +++- src/app/modules/recipes/mix/mix.ts | 18 ++ .../pages/mix/mix-add/mix-add.component.html | 12 +- .../pages/mix/mix-add/mix-add.component.ts | 2 +- .../mix/mix-edit/mix-edit.component.html | 12 +- .../pages/mix/mix-edit/mix-edit.component.ts | 2 +- src/app/modules/recipes/recipes.module.ts | 2 - .../modules/recipes/services/mix.service.ts | 35 ++- .../shared/components/inputs/select.html | 5 +- .../components/tables/position-buttons.html | 4 +- .../shared/components/tables/tables.ts | 2 + src/app/modules/shared/model/recipe.model.ts | 7 +- src/app/modules/shared/units.ts | 4 +- 19 files changed, 123 insertions(+), 394 deletions(-) delete mode 100644 src/app/modules/recipes/components/mix-editor/mix-editor.component.html delete mode 100644 src/app/modules/recipes/components/mix-editor/mix-editor.component.sass delete mode 100644 src/app/modules/recipes/components/mix-editor/mix-editor.component.ts diff --git a/src/app/modules/recipes/components/mix-editor/mix-editor.component.html b/src/app/modules/recipes/components/mix-editor/mix-editor.component.html deleted file mode 100644 index 5e294cd..0000000 --- a/src/app/modules/recipes/components/mix-editor/mix-editor.component.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - Retour - - - Supprimer - Enregistrer - - - - - Ajouter un mélange à la couleur {{recipe.company.name}} - - {{recipe.name}} - Modification du mélange {{mix.mixType.name}} de la - couleur {{recipe.company.name}} - - {{recipe.name}} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Position - {{mixMaterial.position}} - - - - - - Produit - - - - - - - - - - - - - - - Quantité - - - - Unités - - -

%

-
- - - {{units}} - - - - - -
-
- - - - - -
- - - diff --git a/src/app/modules/recipes/components/mix-editor/mix-editor.component.sass b/src/app/modules/recipes/components/mix-editor/mix-editor.component.sass deleted file mode 100644 index 3eb5b9b..0000000 --- a/src/app/modules/recipes/components/mix-editor/mix-editor.component.sass +++ /dev/null @@ -1,6 +0,0 @@ -mat-card - max-width: unset !important - -td.units-wrapper p - width: 3rem - margin-bottom: 0 diff --git a/src/app/modules/recipes/components/mix-editor/mix-editor.component.ts b/src/app/modules/recipes/components/mix-editor/mix-editor.component.ts deleted file mode 100644 index d795617..0000000 --- a/src/app/modules/recipes/components/mix-editor/mix-editor.component.ts +++ /dev/null @@ -1,214 +0,0 @@ -import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core' -import { - Mix, - MixMaterial, - MixMaterialDto, - mixMaterialsAsMixMaterialsDto, - Recipe, - sortMixMaterialsDto -} from '../../../shared/model/recipe.model' -import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' -import {MixService} from '../../services/mix.service' -import {RecipeService} from '../../services/recipe.service' -import {Material, materialComparator} from '../../../shared/model/material.model' -import {MaterialService} from '../../../material/service/material.service' -import {MaterialTypeService} from '../../../material-type/service/material-type.service' -import {FormBuilder, FormControl, Validators} from '@angular/forms' -import {UNIT_MILLILITER} from '../../../shared/units' -import {MatTable} from '@angular/material/table' -import {ActivatedRoute, Router} from '@angular/router' -import {ConfirmBoxComponent} from '../../../shared/components/confirm-box/confirm-box.component' -import {AccountService} from '../../../accounts/services/account.service' -import {ErrorService} from '../../../shared/service/error.service' -import {map} from 'rxjs/operators'; -import {CreInputEntry} from '../../../shared/components/inputs/inputs'; -import {CreForm, ICreForm} from '../../../shared/components/forms/forms'; - -@Component({ - selector: 'cre-mix-editor', - templateUrl: './mix-editor.component.html', - styleUrls: ['./mix-editor.component.sass'] -}) -export class MixEditorComponent extends ErrorHandlingComponent { - @ViewChild(MatTable, {static: true}) mixTable: MatTable - @ViewChild('deleteConfirmBox') deleteConfirmBox: ConfirmBoxComponent - @ViewChild(CreForm) creForm: ICreForm - - @Input() mixId: number | null - @Input() recipe: Recipe - @Input() mix: Mix | null - @Input() materials: Material[] = [] - - @Output() save = new EventEmitter() - - editionMode = false - units = UNIT_MILLILITER - hoveredMixMaterial: MixMaterial | null - tableColumns = ['position', 'buttonsPosition', 'material', 'quantity', 'units', 'buttonRemove'] - - deleting = false - errorHandlers = [{ - filter: error => error.type === 'notfound-mix-id', - consumer: _ => this.urlUtils.navigateTo('/color/list') - }, { - filter: error => error.type === 'exists-material-name', - messageProducer: error => `Un produit avec le nom '${error.name}' existe déjà` - }, { - filter: error => error.type === 'cannotdelete-mix', - messageProducer: _ => 'Ce mélange est utilisé par un ou plusieurs autres mélanges' - }, { - filter: error => error.type === 'invalid-mixmaterial-first', - messageProducer: _ => 'La quantité du premier ingrédient du mélange ne peut pas être exprimée en pourcentage' - }] - - controls: any - materialTypeEntries$ = this.materialTypeService.all.pipe( - map(materialTypes => materialTypes.map(materialType => new CreInputEntry(materialType.id, materialType.name))), - ) - - private _mixMaterials: MixMaterialDto[] = [] - - constructor( - private mixService: MixService, - private recipeService: RecipeService, - private materialService: MaterialService, - private materialTypeService: MaterialTypeService, - private accountService: AccountService, - private formBuilder: FormBuilder, - errorService: ErrorService, - router: Router, - activatedRoute: ActivatedRoute - ) { - super(errorService, activatedRoute, router) - } - - ngOnInit() { - super.ngOnInit() - - this.mixId = this.urlUtils.parseIntUrlParam('id') - if (this.mixId) { - this.editionMode = true - } - - if (this.editionMode) { - this.mix = this.recipe.mixes.find(mix => mix.id === this.mixId) - this.mixMaterials = mixMaterialsAsMixMaterialsDto(this.mix) - } else { - this.addBlankMixMaterial() - } - - this.createControls() - } - - private createControls() { - this.controls = { - name: new FormControl(this.mix?.mixType.name, Validators.required), - materialType: new FormControl(this.mix?.mixType.material.materialType.id, Validators.required) - } - } - - addRow() { - this.addBlankMixMaterial() - this.mixTable.renderRows() - } - - 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() - } - - 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() - } - - 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.controls.name.value, - recipeId: this.recipe.id, - materialTypeId: this.controls.materialType.value, - mixMaterials: this.mixMaterials, - units: this.units - }) - } - - delete() { - this.deleting = true - this.subscribeAndNavigate(this.mixService.delete(this.mixId), `/color/edit/${this.recipe.id}`) - } - - getAvailableMaterials(mixMaterial: MixMaterialDto): CreInputEntry[] { - // return this.materialService.all.pipe( - // map(materials => materials.filter(material => { - // return mixMaterial.materialId === material.id || this.mixMaterials.filter(mm => mm.materialId === material.id).length === 0 - // })), - // map(materials => this.sortedMaterials(materials)), - // map(materials => materials.map(material => new CreInputEntry(material.id, material.name))) - // ) - return this.materials - .filter(m => mixMaterial.materialId === m.id || this.mixMaterials.filter(mm => mm.materialId === m.id).length === 0) - .sort(materialComparator) - .map(material => new CreInputEntry(material.id, material.name)) - // return this.materials.map(material => new CreInputEntry(material.id, material.name)) - // return this.materials - // .filter(m => mixMaterial.materialId === m.id || this.mixMaterials.filter(mm => mm.materialId === m.id).length === 0) - // .sort(materialComparator) - // .map(material => new CreInputEntry(material.id, material.name)) - } - - materialDisplayName(material: Material): string { - if (material.materialType.prefix) { - return `[${material.materialType.prefix}] ${material.name}` - } - return material.name - } - - get mixMaterials(): MixMaterialDto[] { - return this._mixMaterials - } - - set mixMaterials(mixMaterials: MixMaterialDto[]) { - this._mixMaterials = mixMaterials - this.mixTable.renderRows() - } - - private addBlankMixMaterial() { - const mixMaterial = new MixMaterialDto(null, 0, false, this.mixMaterials.length + 1) - this.mixMaterials = [...this.mixMaterials, mixMaterial] - } - - 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/recipes/components/mix-table/mix-table.component.ts b/src/app/modules/recipes/components/mix-table/mix-table.component.ts index 2018c5a..ad5758b 100644 --- a/src/app/modules/recipes/components/mix-table/mix-table.component.ts +++ b/src/app/modules/recipes/components/mix-table/mix-table.component.ts @@ -191,12 +191,13 @@ export class MixTableComponent extends SubscribingComponent { materialId: quantity.materialId, quantity: this.calculateQuantity(index), isPercents: quantity.isPercents, - position: quantity.position + position: quantity.position, + units: UNIT_MILLILITER }) } private convertQuantities(newUnit: string) { - this.mixMaterials.forEach(q => q.quantity = convertMixMaterialQuantity(q, this.units, newUnit)) + this.mixMaterials.forEach(q => q.quantity = convertMixMaterialQuantity(q, newUnit)) this.units = newUnit } diff --git a/src/app/modules/recipes/mix/add.html b/src/app/modules/recipes/mix/add.html index 26639dd..b0b1c5b 100644 --- a/src/app/modules/recipes/mix/add.html +++ b/src/app/modules/recipes/mix/add.html @@ -1,10 +1,10 @@ - Retour + Retour - Enregistrer + Enregistrer diff --git a/src/app/modules/recipes/mix/materials-form.html b/src/app/modules/recipes/mix/materials-form.html index 91d95ca..4c4db10 100644 --- a/src/app/modules/recipes/mix/materials-form.html +++ b/src/app/modules/recipes/mix/materials-form.html @@ -8,7 +8,7 @@ Position - {{mixMaterial.position + 1}} + {{mixMaterial.position}} @@ -16,8 +16,10 @@ diff --git a/src/app/modules/recipes/mix/materials-form.ts b/src/app/modules/recipes/mix/materials-form.ts index 7ecc05c..a90f552 100644 --- a/src/app/modules/recipes/mix/materials-form.ts +++ b/src/app/modules/recipes/mix/materials-form.ts @@ -8,6 +8,7 @@ import {takeUntil} from 'rxjs/operators' import {CreComboBoxComponent, CreInputEntry} from '../../shared/components/inputs/inputs' import {AccountService} from '../../accounts/services/account.service' import {Permission} from '../../shared/model/user' +import {UNIT_MILLILITER} from "../../shared/units"; @Component({ selector: 'cre-mix-materials-form', @@ -51,11 +52,11 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { addRow() { const position = this.nextPosition - const mixMaterial = new MixMaterialDto(null, 0, false, position) + const mixMaterial = new MixMaterialDto(null, 0, false, position, UNIT_MILLILITER) - const materialIdControl = new FormControl(null, Validators.required) - const quantityControl = new FormControl(0, Validators.required) - const unitsControl = new FormControl(null, Validators.required) + const materialIdControl = new FormControl(mixMaterial.materialId, Validators.required) + const quantityControl = new FormControl(mixMaterial.quantity, Validators.required) + const unitsControl = new FormControl(mixMaterial.units, Validators.required) materialIdControl.valueChanges .pipe(takeUntil(this._destroy$)) @@ -85,7 +86,9 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { } removeRow(mixMaterial: MixMaterialDto) { - this.mixMaterials = this.mixMaterials.filter(x => x.position != mixMaterial.position) + this.mixMaterials = this.mixMaterials.filter(x => x.position !== mixMaterial.position) + this._controls = this._controls.filter(x => x.position !== mixMaterial.position) + this._availableMaterialsEntries = this._availableMaterialsEntries.filter(x => x.position !== mixMaterial.position) for (let position = mixMaterial.position + 1; position < this.mixMaterials.length; position++) { this.updatePosition(this.getMixMaterialByPosition(position), position - 1, false) @@ -121,6 +124,23 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { return mixMaterial.materialId ? this._allMaterials.filter(x => x.id === mixMaterial.materialId)[0].materialType.usePercentages : false } + isDecreasePositionButtonDisabled(mixMaterial: MixMaterialDto): boolean { + return mixMaterial.position <= 2 && this.areUnitsPercents(mixMaterial) + } + + isIncreasePositionButtonDisabled(mixMaterial: MixMaterialDto): boolean { + if (mixMaterial.position === this.mixMaterials.length) { + return true + } + + if (mixMaterial.position > 1) { + return false + } + + const nextMixMaterial = this.getMixMaterialByPosition(mixMaterial.position + 1) + return this.areUnitsPercents(nextMixMaterial) + } + get hasMaterialEditPermission(): boolean { return this.accountService.hasPermission(Permission.EDIT_MATERIALS) } @@ -129,6 +149,21 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { return this._allMaterials ? this._allMaterials.length : 0 } + get updatedMixMaterials(): MixMaterialDto[] { + const updatedMixMaterials: MixMaterialDto[] = [] + this.mixMaterials.forEach(mixMaterial => { + const controls = this.getControlsByPosition(mixMaterial.position).controls + updatedMixMaterials.push({ + materialId: controls.materialId.value, + quantity: controls.quantity.value, + position: mixMaterial.position, + units: controls.units.value, + isPercents: this.areUnitsPercents(mixMaterial) + }) + }) + return updatedMixMaterials + } + get valid(): boolean { return this._controls .map(controls => controls.controls) @@ -138,7 +173,7 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { } private get nextPosition(): number { - return this.mixMaterials.length + return this.mixMaterials.length + 1 } private getMixMaterialByPosition(position: number): MixMaterialDto { @@ -170,7 +205,7 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { return this._allMaterials .filter(material => { // Prevent use of percents in first position - if (material.materialType.usePercentages && mixMaterial.position === 0) { + if (material.materialType.usePercentages && mixMaterial.position <= 1) { return false } diff --git a/src/app/modules/recipes/mix/mix.ts b/src/app/modules/recipes/mix/mix.ts index 35ccc73..edee932 100644 --- a/src/app/modules/recipes/mix/mix.ts +++ b/src/app/modules/recipes/mix/mix.ts @@ -14,6 +14,7 @@ import {Material} from '../../shared/model/material.model' import {MaterialService} from '../../material/service/material.service' import {CreForm} from '../../shared/components/forms/forms' import {MixMaterialsForm} from './materials-form' +import {MixSaveDto, MixService} from "../services/mix.service"; @Component({ selector: 'cre-mix-add', @@ -26,6 +27,7 @@ export class MixAdd extends SubscribingComponent { private _recipe: Recipe | null constructor( + private mixService: MixService, private recipeService: RecipeService, private materialTypeService: MaterialTypeService, private materialService: MaterialService, @@ -49,6 +51,13 @@ export class MixAdd extends SubscribingComponent { ) } + submit(dto: MixSaveDto) { + this.subscribeAndNavigate( + this.mixService.saveDto(dto), + `/color/edit/${this.recipe.id}` + ) + } + set recipe(recipe: Recipe) { this._recipe = recipe this.materials$ = this.materialService.getAllForMixCreation(recipe.id) @@ -110,6 +119,15 @@ export class MixForm { @Input() materialTypes: Observable @Input() materials: Observable + get formValues(): MixSaveDto { + return { + name: this.infoForm.mixName, + recipeId: this.recipe.id, + materialTypeId: this.infoForm.mixMaterialTypeId, + mixMaterials: this.mixMaterialsForm.updatedMixMaterials + } + } + get valid(): boolean { return this.infoForm?.valid && this.mixMaterialsForm?.valid } diff --git a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html index 0b94ba5..bfb396a 100644 --- a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html +++ b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html @@ -1,6 +1,6 @@ - - + + + + + + diff --git a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts index 258319e..7a277a9 100644 --- a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts +++ b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts @@ -54,7 +54,7 @@ export class MixAddComponent extends ErrorHandlingComponent { submit(values) { this.subscribeAndNavigate( - this.mixService.saveWithUnits(values.name, values.recipeId, values.materialTypeId, values.mixMaterials, values.units), + this.mixService.saveWithUnits(values.name, values.recipeId, values.materialTypeId, values.mixMaterials), `/color/edit/${this.recipeId}` ) } diff --git a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html index 8133e72..03e26ae 100644 --- a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html +++ b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html @@ -1,6 +1,6 @@ - - + + + + + + diff --git a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts index 1ab2a1b..cf3c1b5 100644 --- a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts +++ b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts @@ -64,7 +64,7 @@ export class MixEditComponent extends ErrorHandlingComponent { } this.subscribeAndNavigate( - this.mixService.updateWithUnits(this.mixId, values.name, values.materialTypeId, values.mixMaterials, values.units), + this.mixService.updateWithUnits(this.mixId, values.name, values.materialTypeId, values.mixMaterials), `/color/edit/${this.recipeId}` ) } diff --git a/src/app/modules/recipes/recipes.module.ts b/src/app/modules/recipes/recipes.module.ts index 2579711..392f961 100644 --- a/src/app/modules/recipes/recipes.module.ts +++ b/src/app/modules/recipes/recipes.module.ts @@ -9,7 +9,6 @@ import {RecipeInfoComponent} from './components/recipe-info/recipe-info.componen import {MixTableComponent} from './components/mix-table/mix-table.component' import {StepListComponent} from './components/step-list/step-list.component' import {StepTableComponent} from './components/step-table/step-table.component' -import {MixEditorComponent} from './components/mix-editor/mix-editor.component' import {UnitSelectorComponent} from './components/unit-selector/unit-selector.component' import {MixAddComponent} from './pages/mix/mix-add/mix-add.component' import {MixEditComponent} from './pages/mix/mix-edit/mix-edit.component' @@ -32,7 +31,6 @@ import {MixMaterialsForm} from "./mix/materials-form"; MixTableComponent, StepListComponent, StepTableComponent, - MixEditorComponent, UnitSelectorComponent, MixAddComponent, MixEditComponent, diff --git a/src/app/modules/recipes/services/mix.service.ts b/src/app/modules/recipes/services/mix.service.ts index cfd57bf..7466673 100644 --- a/src/app/modules/recipes/services/mix.service.ts +++ b/src/app/modules/recipes/services/mix.service.ts @@ -21,8 +21,17 @@ export class MixService { return this.api.get(`/recipe/mix/${id}`) } - saveWithUnits(name: string, recipeId: number, materialTypeId: number, mixMaterials: MixMaterialDto[], units: string): Observable { - return this.save(name, recipeId, materialTypeId, this.convertMixMaterialsToMl(mixMaterials, units)) + saveDto(dto: MixSaveDto): Observable { + return this.saveWithUnits( + dto.name, + dto.recipeId, + dto.materialTypeId, + dto.mixMaterials, + ) + } + + saveWithUnits(name: string, recipeId: number, materialTypeId: number, mixMaterials: MixMaterialDto[]): Observable { + return this.save(name, recipeId, materialTypeId, this.convertMixMaterialsToMl(mixMaterials)) } save(name: string, recipeId: number, materialTypeId: number, mixMaterials: MixMaterialDto[]): Observable { @@ -36,8 +45,8 @@ export class MixService { return this.api.post('/recipe/mix', body) } - updateWithUnits(id: number, name: string, materialTypeId: number, mixMaterials: MixMaterialDto[], units: string): Observable { - return this.update(id, name, materialTypeId, this.convertMixMaterialsToMl(mixMaterials, units)) + updateWithUnits(id: number, name: string, materialTypeId: number, mixMaterials: MixMaterialDto[]): Observable { + return this.update(id, name, materialTypeId, this.convertMixMaterialsToMl(mixMaterials)) } update(id: number, name: string, materialTypeId: number, mixMaterials: MixMaterialDto[]): Observable { @@ -56,11 +65,12 @@ export class MixService { return this.api.delete(`/recipe/mix/${id}`) } - private convertMixMaterialsToMl(mixMaterials: MixMaterialDto[], units: string): MixMaterialDto[] { - return mixMaterials.map(m => { - m.quantity = convertMixMaterialQuantity(m, units, UNIT_MILLILITER) - return m - }) + private convertMixMaterialsToMl(mixMaterials: MixMaterialDto[]): MixMaterialDto[] { + return mixMaterials.map(mixMaterial => ({ + ...mixMaterial, + quantity: convertMixMaterialQuantity(mixMaterial, UNIT_MILLILITER), + units: UNIT_MILLILITER + })) } private appendMixMaterialsToBody(mixMaterials: MixMaterialDto[], body: any) { @@ -74,3 +84,10 @@ export class MixService { } } +export interface MixSaveDto { + name: string + recipeId: number + materialTypeId: number + mixMaterials: MixMaterialDto[] +} + diff --git a/src/app/modules/shared/components/inputs/select.html b/src/app/modules/shared/components/inputs/select.html index e17b4a4..14a03ee 100644 --- a/src/app/modules/shared/components/inputs/select.html +++ b/src/app/modules/shared/components/inputs/select.html @@ -1,14 +1,13 @@ {{label}} - + {{entry.display || entry.value}} - + {{entry.display || entry.value}} diff --git a/src/app/modules/shared/components/tables/position-buttons.html b/src/app/modules/shared/components/tables/position-buttons.html index cb85502..f953d7b 100644 --- a/src/app/modules/shared/components/tables/position-buttons.html +++ b/src/app/modules/shared/components/tables/position-buttons.html @@ -3,14 +3,14 @@ mat-mini-fab color="primary" class="mr-1" - [disabled]="position <= min" + [disabled]="disableDecreaseButton || position <= min" (click)="decreasePosition()"> diff --git a/src/app/modules/shared/components/tables/tables.ts b/src/app/modules/shared/components/tables/tables.ts index b98a7a3..c555716 100644 --- a/src/app/modules/shared/components/tables/tables.ts +++ b/src/app/modules/shared/components/tables/tables.ts @@ -95,6 +95,8 @@ export class CrePositionButtons { @Input() min = 0 @Input() max: number @Input() hidden = false + @Input() disableDecreaseButton = false + @Input() disableIncreaseButton = false @Output() positionChange = new EventEmitter(); diff --git a/src/app/modules/shared/model/recipe.model.ts b/src/app/modules/shared/model/recipe.model.ts index 3b096e0..b0849cd 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 {Company} from './company.model' import {Group} from './user' +import {UNIT_MILLILITER} from "../units"; export class Recipe { public id: number @@ -53,7 +54,8 @@ export class MixMaterialDto { public materialId: number, public quantity: number, public isPercents: boolean, - public position: number + public position: number, + public units: string ) { } } @@ -103,7 +105,8 @@ export function mixMaterialsAsMixMaterialsDto(mix: Mix): MixMaterialDto[] { m.material.id, m.quantity, m.material.materialType.usePercentages, - m.position + m.position, + UNIT_MILLILITER ))) } diff --git a/src/app/modules/shared/units.ts b/src/app/modules/shared/units.ts index 403f136..adbb475 100644 --- a/src/app/modules/shared/units.ts +++ b/src/app/modules/shared/units.ts @@ -25,8 +25,8 @@ export const UNIT_RATIOS = { } } -export function convertMixMaterialQuantity(computedQuantity: MixMaterialDto, from: string, to: string): number { - return !computedQuantity.isPercents ? convertQuantity(computedQuantity.quantity, from, to) : computedQuantity.quantity +export function convertMixMaterialQuantity(mixMaterial: MixMaterialDto, to: string): number { + return !mixMaterial.isPercents ? convertQuantity(mixMaterial.quantity, mixMaterial.units, to) : mixMaterial.quantity } export function convertQuantity(quantity: number, from: string, to: string): number { From e332fee3ba27c83d644f4971dd940bb601b5da17 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Thu, 18 Nov 2021 01:09:35 -0500 Subject: [PATCH 13/28] Add edit support to new mix editor --- .../mix-table/mix-table.component.ts | 4 +- src/app/modules/recipes/mix/add.html | 3 + src/app/modules/recipes/mix/edit.html | 25 ++++ src/app/modules/recipes/mix/form.html | 7 +- src/app/modules/recipes/mix/info-form.html | 5 +- .../recipes/mix/materials-form-combo-box.html | 5 + .../modules/recipes/mix/materials-form.html | 10 +- src/app/modules/recipes/mix/materials-form.ts | 138 ++++++++++-------- src/app/modules/recipes/mix/mix.ts | 73 ++++++--- .../pages/mix/mix-add/mix-add.component.html | 6 - .../pages/mix/mix-add/mix-add.component.sass | 0 .../pages/mix/mix-add/mix-add.component.ts | 61 -------- .../mix/mix-edit/mix-edit.component.html | 6 - .../mix/mix-edit/mix-edit.component.sass | 0 .../pages/mix/mix-edit/mix-edit.component.ts | 75 ---------- .../modules/recipes/recipes-routing.module.ts | 16 +- src/app/modules/recipes/recipes.module.ts | 24 ++- .../modules/recipes/services/mix.service.ts | 16 ++ .../shared/components/inputs/inputs.ts | 16 +- src/app/modules/shared/model/recipe.model.ts | 2 +- 20 files changed, 228 insertions(+), 264 deletions(-) create mode 100644 src/app/modules/recipes/mix/edit.html create mode 100644 src/app/modules/recipes/mix/materials-form-combo-box.html delete mode 100644 src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html delete mode 100644 src/app/modules/recipes/pages/mix/mix-add/mix-add.component.sass delete mode 100644 src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts delete mode 100644 src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html delete mode 100644 src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.sass delete mode 100644 src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts diff --git a/src/app/modules/recipes/components/mix-table/mix-table.component.ts b/src/app/modules/recipes/components/mix-table/mix-table.component.ts index ad5758b..bd430a6 100644 --- a/src/app/modules/recipes/components/mix-table/mix-table.component.ts +++ b/src/app/modules/recipes/components/mix-table/mix-table.component.ts @@ -1,5 +1,5 @@ import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core' -import {Mix, MixMaterial, MixMaterialDto, mixMaterialsAsMixMaterialsDto, Recipe} from '../../../shared/model/recipe.model' +import {Mix, MixMaterial, MixMaterialDto, mixMaterialsToMixMaterialsDto, Recipe} from '../../../shared/model/recipe.model' import {Subject} from 'rxjs' import {SubscribingComponent} from '../../../shared/components/subscribing.component' import {convertMixMaterialQuantity, UNIT_MILLILITER} from '../../../shared/units' @@ -60,7 +60,7 @@ export class MixTableComponent extends SubscribingComponent { this.mixColumns = this.COLUMNS_EDIT } - this.mixMaterials = mixMaterialsAsMixMaterialsDto(this.mix) + this.mixMaterials = mixMaterialsToMixMaterialsDto(this.mix) this.subscribe( this.units$, diff --git a/src/app/modules/recipes/mix/add.html b/src/app/modules/recipes/mix/add.html index b0b1c5b..d6a6301 100644 --- a/src/app/modules/recipes/mix/add.html +++ b/src/app/modules/recipes/mix/add.html @@ -13,5 +13,8 @@ [recipe]="recipe" [materialTypes]="materialTypes$" [materials]="materials$"> + + Ajouter un mélange à la couleur {{recipe.company.name}} - {{recipe.name}} + diff --git a/src/app/modules/recipes/mix/edit.html b/src/app/modules/recipes/mix/edit.html new file mode 100644 index 0000000..14267ca --- /dev/null +++ b/src/app/modules/recipes/mix/edit.html @@ -0,0 +1,25 @@ + + + + Retour + + + + Enregistrer + + + + + + + Modification du mélange {{mix.mixType.name}} de la recette {{recipe.company.name}} - {{recipe.name}} + + + diff --git a/src/app/modules/recipes/mix/form.html b/src/app/modules/recipes/mix/form.html index 0dd72c3..8deb6d4 100644 --- a/src/app/modules/recipes/mix/form.html +++ b/src/app/modules/recipes/mix/form.html @@ -1,8 +1,13 @@ + + + + [materials]="materials" + [mix]="mix"> diff --git a/src/app/modules/recipes/mix/info-form.html b/src/app/modules/recipes/mix/info-form.html index 915b4e1..adb993d 100644 --- a/src/app/modules/recipes/mix/info-form.html +++ b/src/app/modules/recipes/mix/info-form.html @@ -1,6 +1,9 @@ + + + - Ajouter un mélange à la couleur {{recipe.company.name}} - {{recipe.name}} + diff --git a/src/app/modules/recipes/mix/materials-form-combo-box.html b/src/app/modules/recipes/mix/materials-form-combo-box.html new file mode 100644 index 0000000..fc440c9 --- /dev/null +++ b/src/app/modules/recipes/mix/materials-form-combo-box.html @@ -0,0 +1,5 @@ + + diff --git a/src/app/modules/recipes/mix/materials-form.html b/src/app/modules/recipes/mix/materials-form.html index 4c4db10..bba00a4 100644 --- a/src/app/modules/recipes/mix/materials-form.html +++ b/src/app/modules/recipes/mix/materials-form.html @@ -28,10 +28,14 @@ Produit - - + [materials]="allMaterials" + [position]="mixMaterial.position"> + diff --git a/src/app/modules/recipes/mix/materials-form.ts b/src/app/modules/recipes/mix/materials-form.ts index a90f552..06b22d7 100644 --- a/src/app/modules/recipes/mix/materials-form.ts +++ b/src/app/modules/recipes/mix/materials-form.ts @@ -1,6 +1,6 @@ -import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, ViewChild, ViewChildren} from '@angular/core' +import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild, ViewChildren} from '@angular/core' import {CreTable} from '../../shared/components/tables/tables' -import {MixMaterialDto, sortMixMaterialsDto} from '../../shared/model/recipe.model' +import {Mix, MixMaterialDto, mixMaterialsToMixMaterialsDto, sortMixMaterialsDto} from '../../shared/model/recipe.model' import {Observable, Subject} from 'rxjs' import {Material, materialComparator} from '../../shared/model/material.model' import {FormControl, Validators} from '@angular/forms' @@ -8,7 +8,55 @@ import {takeUntil} from 'rxjs/operators' import {CreComboBoxComponent, CreInputEntry} from '../../shared/components/inputs/inputs' import {AccountService} from '../../accounts/services/account.service' import {Permission} from '../../shared/model/user' -import {UNIT_MILLILITER} from "../../shared/units"; +import {UNIT_MILLILITER} from '../../shared/units' + +@Component({ + selector: 'cre-mix-materials-form-combo-box', + templateUrl: 'materials-form-combo-box.html' +}) +export class MixMaterialsFormComboBox implements OnInit { + @ViewChild(CreComboBoxComponent) comboBox: CreComboBoxComponent + + @Input() mixMaterial: MixMaterialDto + @Input() mix: Mix | null + @Input() mixMaterials: MixMaterialDto[] + @Input() control: FormControl + @Input() materials: Material[] + @Input() position: number + + entries: CreInputEntry[] + + ngOnInit() { + this.entries = this.filterMaterials() + } + + updateEntries() { + this.entries = this.filterMaterials() + this.comboBox.reloadEntries() + } + + private filterMaterials(): CreInputEntry[] { + return this.materials + .filter(material => { + if (this.mix && this.mix.mixType.material.id === material.id) { + return false + } + + // Prevent use of percents in first position + if (material.materialType.usePercentages && this.mixMaterial.position <= 1) { + return false + } + + if (this.mixMaterial.materialId === material.id) { + return true + } + + return this.mixMaterials.filter(x => x.materialId === material.id).length <= 0 + }) + .sort(materialComparator) + .map(material => new CreInputEntry(material.id, material.name, material.materialType.prefix ? `[${material.materialType.prefix}] ${material.name}` : material.name)) + } +} @Component({ selector: 'cre-mix-materials-form', @@ -16,16 +64,16 @@ import {UNIT_MILLILITER} from "../../shared/units"; }) export class MixMaterialsForm implements AfterViewInit, OnDestroy { @ViewChild(CreTable) table: CreTable - @ViewChildren(CreComboBoxComponent) materialComboBoxes: CreComboBoxComponent[] + @ViewChildren(MixMaterialsFormComboBox) comboBoxes: MixMaterialsFormComboBox[] @Input() materials: Observable - @Input() mixMaterials: MixMaterialDto[] = [] + @Input() mix: Mix | null + mixMaterials: MixMaterialDto[] = [] columns = ['position', 'positionButtons', 'material', 'quantity', 'units', 'endButton'] + allMaterials: Material[] - private _allMaterials: Material[] private _controls: ControlsByPosition[] = [] - private _availableMaterialsEntries: MaterialEntriesByPosition[] = [] private _destroy$ = new Subject() constructor( @@ -37,9 +85,15 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { ngAfterViewInit() { this.materials.subscribe({ next: materials => { - this._allMaterials = materials + this.allMaterials = materials - this.addRow() + if (!this.mix) { + this.addRow() + } else { + mixMaterialsToMixMaterialsDto(this.mix).forEach(x => this.insertRow(x)) + } + + this.table.renderRows() this.cdRef.detectChanges() } }) @@ -51,9 +105,12 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { } addRow() { - const position = this.nextPosition - const mixMaterial = new MixMaterialDto(null, 0, false, position, UNIT_MILLILITER) + const mixMaterial = new MixMaterialDto(null, 0, false, this.nextPosition, UNIT_MILLILITER) + this.insertRow(mixMaterial) + this.table.renderRows() + } + insertRow(mixMaterial: MixMaterialDto) { const materialIdControl = new FormControl(mixMaterial.materialId, Validators.required) const quantityControl = new FormControl(mixMaterial.quantity, Validators.required) const unitsControl = new FormControl(mixMaterial.units, Validators.required) @@ -65,30 +122,23 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { mixMaterial.materialId = materialId this.refreshAvailableMaterials() this.cdRef.detectChanges() - this.materialComboBoxes.forEach(comboBox => comboBox.reloadEntries()) } }) + this.mixMaterials.push(mixMaterial) this._controls.push({ - position, + position: mixMaterial.position, controls: { materialId: materialIdControl, quantity: quantityControl, units: unitsControl } }) - this._availableMaterialsEntries.push({ - position, - entries: this.filterMaterials(mixMaterial) - }) - this.mixMaterials.push(mixMaterial) - this.table.renderRows() } removeRow(mixMaterial: MixMaterialDto) { this.mixMaterials = this.mixMaterials.filter(x => x.position !== mixMaterial.position) this._controls = this._controls.filter(x => x.position !== mixMaterial.position) - this._availableMaterialsEntries = this._availableMaterialsEntries.filter(x => x.position !== mixMaterial.position) for (let position = mixMaterial.position + 1; position < this.mixMaterials.length; position++) { this.updatePosition(this.getMixMaterialByPosition(position), position - 1, false) @@ -98,7 +148,6 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { updatePosition(mixMaterial: MixMaterialDto, newPosition: number, switchPositions = true) { const currentPosition = mixMaterial.position const currentControls = this.getControlsByPosition(currentPosition) - const currentMaterialEntries = this.getMaterialEntriesByPosition(currentPosition) // Update before current to prevent position conflicts if (switchPositions) { @@ -107,21 +156,21 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { mixMaterial.position = newPosition currentControls.position = newPosition - currentMaterialEntries.position = newPosition this.sortTable() + this.refreshAvailableMaterials() } getControls(position: number): MixMaterialControls { return this.getControlsByPosition(position).controls } - getAvailableMaterialEntries(position: number): CreInputEntry[] { - return this.getMaterialEntriesByPosition(position).entries - } - areUnitsPercents(mixMaterial: MixMaterialDto): boolean { - return mixMaterial.materialId ? this._allMaterials.filter(x => x.id === mixMaterial.materialId)[0].materialType.usePercentages : false + if (!mixMaterial) { + return false + } + + return mixMaterial.materialId ? this.allMaterials?.filter(x => x.id === mixMaterial.materialId)[0].materialType.usePercentages : false } isDecreasePositionButtonDisabled(mixMaterial: MixMaterialDto): boolean { @@ -146,7 +195,7 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { } get materialCount(): number { - return this._allMaterials ? this._allMaterials.length : 0 + return this.allMaterials ? this.allMaterials.length : 0 } get updatedMixMaterials(): MixMaterialDto[] { @@ -184,40 +233,14 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy { return this._controls.filter(control => control.position === position)[0] } - private getMaterialEntriesByPosition(position: number): MaterialEntriesByPosition { - return this._availableMaterialsEntries.filter(control => control.position === position)[0] - } - private refreshAvailableMaterials() { - this.mixMaterials - .sort((a, b) => a.position - b.position) - .forEach(mixMaterial => { - this.getMaterialEntriesByPosition(mixMaterial.position).entries = this.filterMaterials(mixMaterial) - }) + this.comboBoxes.forEach(x => x.updateEntries()) } private sortTable() { this.mixMaterials = sortMixMaterialsDto(this.mixMaterials) this.table.renderRows() } - - private filterMaterials(mixMaterial: MixMaterialDto): CreInputEntry[] { - return this._allMaterials - .filter(material => { - // Prevent use of percents in first position - if (material.materialType.usePercentages && mixMaterial.position <= 1) { - return false - } - - if (mixMaterial.materialId === material.id) { - return true - } - - return this.mixMaterials.filter(x => x.materialId === material.id).length <= 0 - }) - .sort(materialComparator) - .map(material => new CreInputEntry(material.id, material.name, material.materialType.prefix ? `[${material.materialType.prefix}] ${material.name}` : material.name)) - } } interface MixMaterialControls { @@ -230,8 +253,3 @@ interface ControlsByPosition { position: number controls: MixMaterialControls } - -interface MaterialEntriesByPosition { - position: number - entries: CreInputEntry[] -} diff --git a/src/app/modules/recipes/mix/mix.ts b/src/app/modules/recipes/mix/mix.ts index edee932..a91833f 100644 --- a/src/app/modules/recipes/mix/mix.ts +++ b/src/app/modules/recipes/mix/mix.ts @@ -1,6 +1,6 @@ -import {Component, Input, OnInit, ViewChild} from '@angular/core' +import {Component, Directive, Input, OnInit, ViewChild} from '@angular/core' import {SubscribingComponent} from '../../shared/components/subscribing.component' -import {Recipe} from '../../shared/model/recipe.model' +import {Mix, Recipe} from '../../shared/model/recipe.model' import {ErrorService} from '../../shared/service/error.service' import {ActivatedRoute, Router} from '@angular/router' import {RecipeService} from '../services/recipe.service' @@ -14,20 +14,17 @@ import {Material} from '../../shared/model/material.model' import {MaterialService} from '../../material/service/material.service' import {CreForm} from '../../shared/components/forms/forms' import {MixMaterialsForm} from './materials-form' -import {MixSaveDto, MixService} from "../services/mix.service"; +import {MixSaveDto, MixService, MixUpdateDto} from '../services/mix.service' -@Component({ - selector: 'cre-mix-add', - templateUrl: 'add.html' -}) -export class MixAdd extends SubscribingComponent { +@Directive() +abstract class _BaseMixPage extends SubscribingComponent { materialTypes$ = this.materialTypeService.all materials$: Observable private _recipe: Recipe | null constructor( - private mixService: MixService, + protected mixService: MixService, private recipeService: RecipeService, private materialTypeService: MaterialTypeService, private materialService: MaterialService, @@ -51,13 +48,6 @@ export class MixAdd extends SubscribingComponent { ) } - submit(dto: MixSaveDto) { - this.subscribeAndNavigate( - this.mixService.saveDto(dto), - `/color/edit/${this.recipe.id}` - ) - } - set recipe(recipe: Recipe) { this._recipe = recipe this.materials$ = this.materialService.getAllForMixCreation(recipe.id) @@ -66,6 +56,51 @@ export class MixAdd extends SubscribingComponent { get recipe(): Recipe { return this._recipe } + + abstract submit(dto: MixSaveDto) +} + +@Component({ + selector: 'cre-mix-add', + templateUrl: 'add.html' +}) +export class MixAdd extends _BaseMixPage { + submit(dto: MixSaveDto) { + this.subscribeAndNavigate( + this.mixService.saveDto(dto), + `/color/edit/${this.recipe.id}` + ) + } +} + +@Component({ + selector: 'cre-mix-edit', + templateUrl: 'edit.html' +}) +export class MixEdit extends _BaseMixPage { + mix: Mix + + ngOnInit() { + super.ngOnInit() + + this.fetchMix() + } + + private fetchMix() { + const mixId = this.urlUtils.parseIntUrlParam('id') + + this.subscribe( + this.mixService.getById(mixId), + mix => this.mix = mix + ) + } + + submit(dto: MixSaveDto) { + this.subscribeAndNavigate( + this.mixService.updateDto({...dto, id: this.mix.id}), + `/color/edit/${this.recipe.id}` + ) + } } @Component({ @@ -76,6 +111,7 @@ export class MixInfoForm implements OnInit { @ViewChild(CreForm) form: CreForm @Input() recipe: Recipe + @Input() mix: Mix | null @Input() materialTypes: Observable materialTypeEntries: Observable @@ -89,8 +125,8 @@ export class MixInfoForm implements OnInit { ) this.controls = { - name: new FormControl(null, Validators.required), - materialType: new FormControl(null, Validators.required) + name: new FormControl(this.mix?.mixType.name, Validators.required), + materialType: new FormControl(this.mix?.mixType.material.materialType.id, Validators.required) } } @@ -116,6 +152,7 @@ export class MixForm { @ViewChild(MixMaterialsForm) mixMaterialsForm: MixMaterialsForm @Input() recipe: Recipe + @Input() mix: Mix | null @Input() materialTypes: Observable @Input() materials: Observable diff --git a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html deleted file mode 100644 index bfb396a..0000000 --- a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.html +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.sass b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.sass deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts b/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts deleted file mode 100644 index 7a277a9..0000000 --- a/src/app/modules/recipes/pages/mix/mix-add/mix-add.component.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {Component} from '@angular/core' -import {Material} from '../../../../shared/model/material.model' -import {MaterialService} from '../../../../material/service/material.service' -import {ActivatedRoute, Router} from '@angular/router' -import {ErrorHandlingComponent} from '../../../../shared/components/subscribing.component' -import {MixService} from '../../../services/mix.service' -import {ErrorService} from '../../../../shared/service/error.service' -import {Recipe} from "../../../../shared/model/recipe.model"; -import {RecipeService} from "../../../services/recipe.service"; - -@Component({ - selector: 'cre-mix-add', - templateUrl: './mix-add.component.html', - styleUrls: ['./mix-add.component.sass'] -}) -export class MixAddComponent extends ErrorHandlingComponent { - materials: Material[] | null = [new Material(0, "Example", 1000, null, null)] - recipe: Recipe | null - - private recipeId: number | null - - constructor( - private recipeService: RecipeService, - private materialService: MaterialService, - private mixService: MixService, - errorService: ErrorService, - router: Router, - activatedRoute: ActivatedRoute - ) { - super(errorService, activatedRoute, router) - } - - ngOnInit(): void { - super.ngOnInit() - - this.recipeId = this.urlUtils.parseIntUrlParam('recipeId') - this.fetchRecipe() - // this.fetchMaterials() - } - - private fetchRecipe() { - this.subscribe( - this.recipeService.getById(this.recipeId), - recipe => this.recipe = recipe - ) - } - - private fetchMaterials() { - this.subscribe( - this.materialService.getAllForMixCreation(this.recipeId), - materials => this.materials = materials - ) - } - - submit(values) { - this.subscribeAndNavigate( - this.mixService.saveWithUnits(values.name, values.recipeId, values.materialTypeId, values.mixMaterials), - `/color/edit/${this.recipeId}` - ) - } -} diff --git a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html deleted file mode 100644 index 03e26ae..0000000 --- a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.html +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.sass b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.sass deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts b/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts deleted file mode 100644 index cf3c1b5..0000000 --- a/src/app/modules/recipes/pages/mix/mix-edit/mix-edit.component.ts +++ /dev/null @@ -1,75 +0,0 @@ -import {Component} from '@angular/core' -import {ActivatedRoute, Router} from '@angular/router' -import {ErrorHandlingComponent} from '../../../../shared/components/subscribing.component' -import {Material} from '../../../../shared/model/material.model' -import {MaterialService} from '../../../../material/service/material.service' -import {MixService} from '../../../services/mix.service' -import {ErrorService} from '../../../../shared/service/error.service' -import {MixMaterialDto, Recipe} from '../../../../shared/model/recipe.model' -import {AlertService} from '../../../../shared/service/alert.service' -import {RecipeService} from "../../../services/recipe.service"; - -@Component({ - selector: 'cre-mix-edit', - templateUrl: './mix-edit.component.html', - styleUrls: ['./mix-edit.component.sass'] -}) -export class MixEditComponent extends ErrorHandlingComponent { - mixId: number | null - recipe: Recipe | null - materials: Material[] | null - - private recipeId: number | null - - constructor( - private recipeService: RecipeService, - private materialService: MaterialService, - private mixService: MixService, - private alertService: AlertService, - errorService: ErrorService, - router: Router, - activatedRoute: ActivatedRoute - ) { - super(errorService, activatedRoute, router) - } - - ngOnInit(): void { - super.ngOnInit() - - this.mixId = this.urlUtils.parseIntUrlParam('id') - this.recipeId = this.urlUtils.parseIntUrlParam('recipeId') - - this.fetchRecipe() - this.fetchMaterials() - } - - private fetchRecipe() { - this.subscribe( - this.recipeService.getById(this.recipeId), - recipe => this.recipe = recipe - ) - } - - private fetchMaterials() { - this.subscribe( - this.materialService.getAllForMixUpdate(this.mixId), - materials => this.materials = materials - ) - } - - 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), - `/color/edit/${this.recipeId}` - ) - } - - private mixMaterialsPositionAreValid(mixMaterials: MixMaterialDto[]): boolean { - return !mixMaterials.find(m => m.position <= 0) - } -} diff --git a/src/app/modules/recipes/recipes-routing.module.ts b/src/app/modules/recipes/recipes-routing.module.ts index 75657d8..dca257e 100644 --- a/src/app/modules/recipes/recipes-routing.module.ts +++ b/src/app/modules/recipes/recipes-routing.module.ts @@ -1,11 +1,9 @@ -import {NgModule} from '@angular/core'; -import {RouterModule, Routes} from '@angular/router'; -import {CreRecipeExplore} from './explore'; -import {MixEditComponent} from './pages/mix/mix-edit/mix-edit.component'; -import {MixAddComponent} from './pages/mix/mix-add/mix-add.component'; -import {RecipeAdd, RecipeEdit} from './recipes'; -import {RecipeList} from './list'; -import {MixAdd} from "./mix/mix"; +import {NgModule} from '@angular/core' +import {RouterModule, Routes} from '@angular/router' +import {CreRecipeExplore} from './explore' +import {RecipeAdd, RecipeEdit} from './recipes' +import {RecipeList} from './list' +import {MixAdd, MixEdit} from './mix/mix' const routes: Routes = [{ path: 'list', @@ -21,7 +19,7 @@ const routes: Routes = [{ component: MixAdd }, { path: 'edit/mix/:recipeId/:id', - component: MixEditComponent + component: MixEdit }, { path: 'explore/:id', component: CreRecipeExplore diff --git a/src/app/modules/recipes/recipes.module.ts b/src/app/modules/recipes/recipes.module.ts index 392f961..d1787b2 100644 --- a/src/app/modules/recipes/recipes.module.ts +++ b/src/app/modules/recipes/recipes.module.ts @@ -10,19 +10,17 @@ import {MixTableComponent} from './components/mix-table/mix-table.component' import {StepListComponent} from './components/step-list/step-list.component' import {StepTableComponent} from './components/step-table/step-table.component' import {UnitSelectorComponent} from './components/unit-selector/unit-selector.component' -import {MixAddComponent} from './pages/mix/mix-add/mix-add.component' -import {MixEditComponent} from './pages/mix/mix-edit/mix-edit.component' import {ImagesEditorComponent} from './components/images-editor/images-editor.component' import {MixesCardComponent} from './components/mixes-card/mixes-card.component' import {MatSortModule} from '@angular/material/sort' -import {CreInputsModule} from '../shared/components/inputs/inputs.module'; -import {CreButtonsModule} from '../shared/components/buttons/buttons.module'; -import {RecipeAdd, RecipeEdit, RecipeForm} from './recipes'; -import {CreActionBarModule} from '../shared/components/action-bar/action-bar.module'; -import {RecipeList} from './list'; -import {MixAdd, MixForm, MixInfoForm} from "./mix/mix"; -import {CreTablesModule} from "../shared/components/tables/tables.module"; -import {MixMaterialsForm} from "./mix/materials-form"; +import {CreInputsModule} from '../shared/components/inputs/inputs.module' +import {CreButtonsModule} from '../shared/components/buttons/buttons.module' +import {RecipeAdd, RecipeEdit, RecipeForm} from './recipes' +import {CreActionBarModule} from '../shared/components/action-bar/action-bar.module' +import {RecipeList} from './list' +import {MixAdd, MixEdit, MixForm, MixInfoForm} from './mix/mix' +import {CreTablesModule} from '../shared/components/tables/tables.module' +import {MixMaterialsForm, MixMaterialsFormComboBox} from './mix/materials-form' @NgModule({ declarations: [ @@ -32,8 +30,6 @@ import {MixMaterialsForm} from "./mix/materials-form"; StepListComponent, StepTableComponent, UnitSelectorComponent, - MixAddComponent, - MixEditComponent, ImagesEditorComponent, MixesCardComponent, RecipeForm, @@ -41,9 +37,11 @@ import {MixMaterialsForm} from "./mix/materials-form"; RecipeEdit, RecipeList, MixAdd, + MixEdit, MixForm, MixInfoForm, - MixMaterialsForm + MixMaterialsForm, + MixMaterialsFormComboBox ], exports: [ UnitSelectorComponent diff --git a/src/app/modules/recipes/services/mix.service.ts b/src/app/modules/recipes/services/mix.service.ts index 7466673..6a523e1 100644 --- a/src/app/modules/recipes/services/mix.service.ts +++ b/src/app/modules/recipes/services/mix.service.ts @@ -45,6 +45,15 @@ export class MixService { return this.api.post('/recipe/mix', body) } + updateDto(dto: MixUpdateDto): Observable { + return this.updateWithUnits( + dto.id, + dto.name, + dto.materialTypeId, + dto.mixMaterials + ) + } + updateWithUnits(id: number, name: string, materialTypeId: number, mixMaterials: MixMaterialDto[]): Observable { return this.update(id, name, materialTypeId, this.convertMixMaterialsToMl(mixMaterials)) } @@ -91,3 +100,10 @@ export interface MixSaveDto { mixMaterials: MixMaterialDto[] } +export interface MixUpdateDto { + id: number + name: string + materialTypeId: number + mixMaterials: MixMaterialDto[] +} + diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts index df922cd..cfca06f 100644 --- a/src/app/modules/shared/components/inputs/inputs.ts +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -196,14 +196,6 @@ export class CreComboBoxComponent { return } - if (this.control.value) { - this.internalControl.setValue(this.findEntryByKey(this.control.value)?.value) - } - - if (this.control.disabled) { - this.internalControl.disable() - } - this.internalControl = new FormControl({ value: null, disabled: false @@ -222,6 +214,14 @@ export class CreComboBoxComponent { } }) + if (this.control.value) { + this.internalControl.setValue(this.findEntryByKey(this.control.value)?.value) + } + + if (this.control.disabled) { + this.internalControl.disable() + } + this.reloadEntries() this._controlsInitialized = true } diff --git a/src/app/modules/shared/model/recipe.model.ts b/src/app/modules/shared/model/recipe.model.ts index b0849cd..a1bfeb5 100644 --- a/src/app/modules/shared/model/recipe.model.ts +++ b/src/app/modules/shared/model/recipe.model.ts @@ -100,7 +100,7 @@ export function sortRecipeSteps(steps: RecipeStep[]): RecipeStep[] { return steps.sort((a, b) => a.position - b.position) } -export function mixMaterialsAsMixMaterialsDto(mix: Mix): MixMaterialDto[] { +export function mixMaterialsToMixMaterialsDto(mix: Mix): MixMaterialDto[] { return sortMixMaterialsDto(mix.mixMaterials.map(m => new MixMaterialDto( m.material.id, m.quantity, From a0d15b57fbb3285899355868686568b2109923e8 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 23 Nov 2021 12:04:10 -0500 Subject: [PATCH 14/28] Add no entity warning for companies and inventory --- .../modules/company/pages/list/list.component.html | 5 +++++ src/app/modules/company/pages/list/list.component.ts | 11 +++++++++++ .../material/pages/inventory/inventory.component.html | 7 +++++++ .../material/pages/inventory/inventory.component.ts | 2 +- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/app/modules/company/pages/list/list.component.html b/src/app/modules/company/pages/list/list.component.html index e0781de..b545a0a 100644 --- a/src/app/modules/company/pages/list/list.component.html +++ b/src/app/modules/company/pages/list/list.component.html @@ -1,3 +1,8 @@ + +

Il n'y a actuellement aucune bannière enregistrée dans le système.

+

Vous pouvez en créer une ici.

+
+ this.companiesEmpty = companies.length <= 0)) + } + + get hasEditPermission(): boolean { + return this.accountService.hasPermission(Permission.EDIT_COMPANIES) } } diff --git a/src/app/modules/material/pages/inventory/inventory.component.html b/src/app/modules/material/pages/inventory/inventory.component.html index a964091..dd49bc1 100644 --- a/src/app/modules/material/pages/inventory/inventory.component.html +++ b/src/app/modules/material/pages/inventory/inventory.component.html @@ -45,7 +45,14 @@
+ +

Il n'y a actuellement aucun produit enregistré dans le système.

+

Vous pouvez en créer un ici. +

+
+ From ba360529ccb80b3a8faf21161984e545632dab2b Mon Sep 17 00:00:00 2001 From: FyloZ Date: Tue, 30 Nov 2021 23:34:06 -0500 Subject: [PATCH 15/28] Update company list --- docker-compose.yml | 18 ++++++------ src/app/modules/company/company.module.ts | 8 +++++- .../company/pages/list/list.component.html | 28 ++++++++++++++----- .../company/pages/list/list.component.ts | 16 +++++------ src/app/modules/shared/shared.module.ts | 1 + 5 files changed, 46 insertions(+), 25 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 333e1ea..b6c8985 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,15 +1,7 @@ version: "3.1" services: - database: - image: mysql - command: --default-authentication-plugin=mysql_native_password - environment: - MYSQL_ROOT_PASSWORD: "pass" - MYSQL_DATABASE: "cre" - ports: - - "3307:3306" - backend: + cre.backend: image: registry.fyloz.dev:5443/colorrecipesexplorer/backend:latest environment: spring_profiles_active: "mysql,debug" @@ -23,6 +15,14 @@ services: volumes: - cre_data:/usr/bin/cre/data - cre_config:/usr/bin/cre/config + cre.database: + image: mysql + command: --default-authentication-plugin=mysql_native_password + environment: + MYSQL_ROOT_PASSWORD: "pass" + MYSQL_DATABASE: "cre" + ports: + - "3307:3306" volumes: cre_data: diff --git a/src/app/modules/company/company.module.ts b/src/app/modules/company/company.module.ts index 4d86746..5f9d07b 100644 --- a/src/app/modules/company/company.module.ts +++ b/src/app/modules/company/company.module.ts @@ -5,6 +5,9 @@ import { AddComponent } from './pages/add/add.component'; import { EditComponent } from './pages/edit/edit.component'; import {CompanyRoutingModule} from "./company-routing.module"; import {SharedModule} from "../shared/shared.module"; +import {CreActionBarModule} from '../shared/components/action-bar/action-bar.module' +import {CreButtonsModule} from '../shared/components/buttons/buttons.module' +import {CreTablesModule} from '../shared/components/tables/tables.module' @@ -13,7 +16,10 @@ import {SharedModule} from "../shared/shared.module"; imports: [ CommonModule, CompanyRoutingModule, - SharedModule + SharedModule, + CreActionBarModule, + CreButtonsModule, + CreTablesModule ] }) export class CompanyModule { } diff --git a/src/app/modules/company/pages/list/list.component.html b/src/app/modules/company/pages/list/list.component.html index b545a0a..fc9e37c 100644 --- a/src/app/modules/company/pages/list/list.component.html +++ b/src/app/modules/company/pages/list/list.component.html @@ -1,12 +1,26 @@ + + + Ajouter + + +

Il n'y a actuellement aucune bannière enregistrée dans le système.

Vous pouvez en créer une ici.

- - + + +
+ + + + + + + + diff --git a/src/app/modules/company/pages/list/list.component.ts b/src/app/modules/company/pages/list/list.component.ts index 64e55ec..5279a3f 100644 --- a/src/app/modules/company/pages/list/list.component.ts +++ b/src/app/modules/company/pages/list/list.component.ts @@ -5,8 +5,8 @@ import {Permission} from '../../../shared/model/user' import {ActivatedRoute, Router} from '@angular/router' import {ErrorService} from '../../../shared/service/error.service' import {AppState} from '../../../shared/app-state' -import {map, tap} from "rxjs/operators"; -import {AccountService} from "../../../accounts/services/account.service"; +import {tap} from 'rxjs/operators' +import {AccountService} from '../../../accounts/services/account.service' @Component({ selector: 'cre-list', @@ -14,10 +14,12 @@ import {AccountService} from "../../../accounts/services/account.service"; styleUrls: ['./list.component.sass'] }) export class ListComponent extends ErrorHandlingComponent { - companies$ = this.companyService.all - columns = [ - {def: 'name', title: 'Nom', valueFn: c => c.name} - ] + companies$ = this.companyService.all.pipe(tap(companies => this.companiesEmpty = companies.length <= 0)) + + // columns = [ + // {def: 'name', title: 'Nom', valueFn: c => c.name} + // ] + columns = ['name', 'editButton'] buttons = [{ text: 'Modifier', linkFn: t => `/catalog/company/edit/${t.id}`, @@ -36,8 +38,6 @@ export class ListComponent extends ErrorHandlingComponent { ) { super(errorService, activatedRoute, router) this.appState.title = 'Bannières' - - this.companies$.pipe(tap(companies => this.companiesEmpty = companies.length <= 0)) } get hasEditPermission(): boolean { diff --git a/src/app/modules/shared/shared.module.ts b/src/app/modules/shared/shared.module.ts index d30b0b4..be216ae 100644 --- a/src/app/modules/shared/shared.module.ts +++ b/src/app/modules/shared/shared.module.ts @@ -38,6 +38,7 @@ import {VarDirective} from './directives/var.directive' import {CreColorPreview} from './components/color-preview/color-preview' import {CreDialogsModule} from './components/dialogs/dialogs.module' import {CreAlertsModule} from './components/alerts/alerts.module'; +import {CreActionBarModule} from './components/action-bar/action-bar.module' @NgModule({ declarations: [VarDirective, HeaderComponent, UserMenuComponent, LabeledIconComponent, ConfirmBoxComponent, PermissionsListComponent, PermissionsFieldComponent, NavComponent, EntityListComponent, EntityAddComponent, EntityEditComponent, FileButtonComponent, GlobalAlertHandlerComponent, SliderFieldComponent, LoadingWheelComponent, CreColorPreview], From 4ccdd090c1c6e6ff9cc58cf8a12a494961c38ad0 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 1 Dec 2021 00:10:23 -0500 Subject: [PATCH 16/28] Update material type list --- .../company/pages/list/list.component.html | 2 +- .../company/pages/list/list.component.ts | 13 +---- .../material-type/material-type.module.ts | 8 +++- .../pages/list/list.component.html | 47 ++++++++++++++++--- .../pages/list/list.component.ts | 27 +++++------ 5 files changed, 63 insertions(+), 34 deletions(-) diff --git a/src/app/modules/company/pages/list/list.component.html b/src/app/modules/company/pages/list/list.component.html index fc9e37c..7cb13dd 100644 --- a/src/app/modules/company/pages/list/list.component.html +++ b/src/app/modules/company/pages/list/list.component.html @@ -17,7 +17,7 @@ - + + + + + + + + + + + + + + + + + + diff --git a/src/app/modules/material-type/pages/list/list.component.ts b/src/app/modules/material-type/pages/list/list.component.ts index 2556388..c25e58f 100644 --- a/src/app/modules/material-type/pages/list/list.component.ts +++ b/src/app/modules/material-type/pages/list/list.component.ts @@ -5,6 +5,8 @@ import {Permission} from '../../../shared/model/user' import {ActivatedRoute, Router} from '@angular/router' import {ErrorService} from '../../../shared/service/error.service' import {AppState} from '../../../shared/app-state' +import {tap} from 'rxjs/operators' +import {AccountService} from '../../../accounts/services/account.service' @Component({ selector: 'cre-list', @@ -12,23 +14,16 @@ import {AppState} from '../../../shared/app-state' styleUrls: ['./list.component.sass'] }) export class ListComponent extends ErrorHandlingComponent { - materialTypes$ = this.materialTypeService.all - columns = [ - {def: 'name', title: 'Nom', valueFn: t => t.name}, - {def: 'prefix', title: 'Préfixe', valueFn: t => t.prefix}, - {def: 'usePercentages', title: 'Utilise les pourcentages', valueFn: t => t.usePercentages ? 'Oui' : 'Non'} - ] - buttons = [ - { - text: 'Modifier', - linkFn: t => `/catalog/materialtype/edit/${t.id}`, - permission: Permission.EDIT_MATERIAL_TYPES, - disabledFn: t => t.systemType - } - ] + materialTypes$ = this.materialTypeService.all.pipe( + tap(materialTypes => this.materialTypesEmpty = materialTypes.length <= 0) + ) + materialTypesEmpty = false + + columns = ['name', 'prefix', 'usePercentages', 'editButton'] constructor( private materialTypeService: MaterialTypeService, + private accountService: AccountService, private appState: AppState, errorService: ErrorService, router: Router, @@ -37,4 +32,8 @@ export class ListComponent extends ErrorHandlingComponent { super(errorService, activatedRoute, router) this.appState.title = 'Types de produit' } + + get hasEditPermission(): boolean { + return this.accountService.hasPermission(Permission.EDIT_COMPANIES) + } } From f564c37b159b0d73f0b82f06c54354db34859434 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 1 Dec 2021 10:55:45 -0500 Subject: [PATCH 17/28] Update recipe list --- .../company/pages/list/list.component.html | 2 +- .../pages/list/list.component.html | 2 +- src/app/modules/recipes/list.html | 20 +++--- src/app/modules/recipes/list.ts | 72 ++++++++----------- .../modules/recipes/mix/materials-form.html | 2 +- src/app/modules/recipes/recipes.sass | 12 ++++ .../shared/components/tables/table.html | 4 +- .../shared/components/tables/tables.module.ts | 14 ++-- .../shared/components/tables/tables.ts | 31 ++++++-- src/app/modules/shared/model/recipe.model.ts | 5 ++ .../modules/touch-up-kit/pages/details.html | 2 +- src/app/modules/touch-up-kit/pages/list.html | 4 +- 12 files changed, 97 insertions(+), 73 deletions(-) diff --git a/src/app/modules/company/pages/list/list.component.html b/src/app/modules/company/pages/list/list.component.html index 7cb13dd..1fc8be5 100644 --- a/src/app/modules/company/pages/list/list.component.html +++ b/src/app/modules/company/pages/list/list.component.html @@ -9,7 +9,7 @@

Vous pouvez en créer une ici.

- +
diff --git a/src/app/modules/material-type/pages/list/list.component.html b/src/app/modules/material-type/pages/list/list.component.html index 23dbe99..bf32816 100644 --- a/src/app/modules/material-type/pages/list/list.component.html +++ b/src/app/modules/material-type/pages/list/list.component.html @@ -12,7 +12,7 @@ diff --git a/src/app/modules/recipes/list.html b/src/app/modules/recipes/list.html index 4ad8ce1..81d7de1 100644 --- a/src/app/modules/recipes/list.html +++ b/src/app/modules/recipes/list.html @@ -36,7 +36,12 @@ -
Nom{{company.name}} + + Modifier + + + Modifier diff --git a/src/app/modules/company/pages/list/list.component.ts b/src/app/modules/company/pages/list/list.component.ts index 5279a3f..5899e96 100644 --- a/src/app/modules/company/pages/list/list.component.ts +++ b/src/app/modules/company/pages/list/list.component.ts @@ -15,19 +15,10 @@ import {AccountService} from '../../../accounts/services/account.service' }) export class ListComponent extends ErrorHandlingComponent { companies$ = this.companyService.all.pipe(tap(companies => this.companiesEmpty = companies.length <= 0)) - - // columns = [ - // {def: 'name', title: 'Nom', valueFn: c => c.name} - // ] - columns = ['name', 'editButton'] - buttons = [{ - text: 'Modifier', - linkFn: t => `/catalog/company/edit/${t.id}`, - permission: Permission.EDIT_COMPANIES - }] - companiesEmpty = false + columns = ['name', 'editButton'] + constructor( private companyService: CompanyService, private accountService: AccountService, diff --git a/src/app/modules/material-type/material-type.module.ts b/src/app/modules/material-type/material-type.module.ts index 591a8a8..1df904c 100644 --- a/src/app/modules/material-type/material-type.module.ts +++ b/src/app/modules/material-type/material-type.module.ts @@ -6,6 +6,9 @@ import { ListComponent } from './pages/list/list.component'; import {SharedModule} from "../shared/shared.module"; import { AddComponent } from './pages/add/add.component'; import { EditComponent } from './pages/edit/edit.component'; +import {CreActionBarModule} from '../shared/components/action-bar/action-bar.module' +import {CreButtonsModule} from '../shared/components/buttons/buttons.module' +import {CreTablesModule} from '../shared/components/tables/tables.module' @NgModule({ @@ -13,7 +16,10 @@ import { EditComponent } from './pages/edit/edit.component'; imports: [ CommonModule, MaterialTypeRoutingModule, - SharedModule + SharedModule, + CreActionBarModule, + CreButtonsModule, + CreTablesModule ] }) export class MaterialTypeModule { } diff --git a/src/app/modules/material-type/pages/list/list.component.html b/src/app/modules/material-type/pages/list/list.component.html index f70251f..23dbe99 100644 --- a/src/app/modules/material-type/pages/list/list.component.html +++ b/src/app/modules/material-type/pages/list/list.component.html @@ -1,7 +1,40 @@ - - + + + Ajouter + + + + +

Il n'y a actuellement aucun type de produit enregistré dans le système.

+

Vous pouvez en créer un ici.

+
+ + + +
Nom{{materialType.name}}Préfix{{materialType.prefix}}Utilise les pourcentages{{materialType.usePercentages ? 'Oui' : 'Non'}} + + Modifier + + Nom {{company.name}}Nom
+ @@ -84,19 +89,16 @@ - - - - - -
Nom - + + Voir - + + Modifier
+ diff --git a/src/app/modules/recipes/list.ts b/src/app/modules/recipes/list.ts index 051212f..121f6e7 100644 --- a/src/app/modules/recipes/list.ts +++ b/src/app/modules/recipes/list.ts @@ -1,17 +1,17 @@ -import {ChangeDetectorRef, Component} from '@angular/core'; -import {ErrorHandlingComponent} from '../shared/components/subscribing.component'; -import {Company} from '../shared/model/company.model'; -import {getRecipeLuma, Recipe} from '../shared/model/recipe.model'; -import {CompanyService} from '../company/service/company.service'; -import {RecipeService} from './services/recipe.service'; -import {AccountService} from '../accounts/services/account.service'; -import {ConfigService} from '../shared/service/config.service'; -import {AppState} from '../shared/app-state'; -import {ErrorService} from '../shared/service/error.service'; -import {ActivatedRoute, Router} from '@angular/router'; -import {Config} from '../shared/model/config.model'; -import {Permission} from '../shared/model/user'; -import {FormControl} from '@angular/forms'; +import {ChangeDetectorRef, Component} from '@angular/core' +import {ErrorHandlingComponent} from '../shared/components/subscribing.component' +import {Company} from '../shared/model/company.model' +import {getRecipeLuma, Recipe, recipeMatchesFilter} from '../shared/model/recipe.model' +import {CompanyService} from '../company/service/company.service' +import {RecipeService} from './services/recipe.service' +import {AccountService} from '../accounts/services/account.service' +import {ConfigService} from '../shared/service/config.service' +import {AppState} from '../shared/app-state' +import {ErrorService} from '../shared/service/error.service' +import {ActivatedRoute, Router} from '@angular/router' +import {Config} from '../shared/model/config.model' +import {Permission} from '../shared/model/user' +import {FormControl} from '@angular/forms' @Component({ selector: 'cre-recipe-list', @@ -21,12 +21,13 @@ import {FormControl} from '@angular/forms'; export class RecipeList extends ErrorHandlingComponent { companies: Company[] = [] recipes: Map = new Map() - tableCols = ['name', 'description', 'color', 'sample', 'iconNotApproved', 'buttonView', 'buttonEdit'] - searchQuery = '' + columns = ['name', 'description', 'color', 'sample', 'iconNotApproved', 'buttonView', 'buttonEdit'] panelForcedExpanded = false - hiddenRecipes = [] searchControl: FormControl + searchQuery = '' + + recipeFilterPredicate = recipeMatchesFilter constructor( private companyService: CompanyService, @@ -62,7 +63,13 @@ export class RecipeList extends ErrorHandlingComponent { this.searchControl = new FormControl('') this.subscribe( this.searchControl.valueChanges, - value => this.searchRecipes(value) + value => { + this.searchQuery = value + if (value.length > 0 && !this.panelForcedExpanded) { + this.panelForcedExpanded = true + this.cdRef.detectChanges() + } + } ) } @@ -81,25 +88,14 @@ export class RecipeList extends ErrorHandlingComponent { ) } - searchRecipes(searchQuery) { - this.searchQuery = searchQuery - if (this.searchQuery.length > 0 && !this.panelForcedExpanded) { - this.panelForcedExpanded = true - this.cdRef.detectChanges() - } - - for (let recipeArray of this.recipes.values()) { - recipeArray.forEach(recipe => this.recipeMatchesSearchQuery(recipe)) - } - } - isCompanyHidden(company: Company): boolean { - const companyRecipes = this.recipes.get(company.id); + const companyRecipes = this.recipes.get(company.id) return !(companyRecipes && companyRecipes.length >= 0) || this.searchQuery && this.searchQuery.length > 0 && - companyRecipes.map(r => this.hiddenRecipes[r.id]).filter(r => !r).length <= 0 + !companyRecipes.some(recipe => this.recipeFilterPredicate(recipe, this.searchQuery)) } + isLight(recipe: Recipe): boolean { return getRecipeLuma(recipe) > 200 } @@ -111,16 +107,4 @@ export class RecipeList extends ErrorHandlingComponent { get hasCompanyEditPermission(): boolean { return this.accountService.hasPermission(Permission.EDIT_COMPANIES) } - - private recipeMatchesSearchQuery(recipe: Recipe) { - const matches = this.searchString(recipe.company.name) || - this.searchString(recipe.name) || - this.searchString(recipe.description) || - (recipe.sample && this.searchString(recipe.sample.toString())) - this.hiddenRecipes[recipe.id] = !matches - } - - private searchString(value: string): boolean { - return value.toLowerCase().indexOf(this.searchQuery.toLowerCase()) >= 0 - } } diff --git a/src/app/modules/recipes/mix/materials-form.html b/src/app/modules/recipes/mix/materials-form.html index bba00a4..5c7742c 100644 --- a/src/app/modules/recipes/mix/materials-form.html +++ b/src/app/modules/recipes/mix/materials-form.html @@ -5,7 +5,7 @@

- + Position {{mixMaterial.position}} diff --git a/src/app/modules/recipes/recipes.sass b/src/app/modules/recipes/recipes.sass index 353d3df..44c8af6 100644 --- a/src/app/modules/recipes/recipes.sass +++ b/src/app/modules/recipes/recipes.sass @@ -16,3 +16,15 @@ mat-expansion-panel .recipe-content > div margin: 0 3rem 3rem + +cre-table + .mat-column-name, + .mat-column-color, + .mat-column-iconNotApproved + width: 5em + + .mat-column-description + width: 50em + + .mat-column-sample + width: 10em diff --git a/src/app/modules/shared/components/tables/table.html b/src/app/modules/shared/components/tables/table.html index 46560ec..9c9a748 100644 --- a/src/app/modules/shared/components/tables/table.html +++ b/src/app/modules/shared/components/tables/table.html @@ -1,4 +1,6 @@ - +
diff --git a/src/app/modules/shared/components/tables/tables.module.ts b/src/app/modules/shared/components/tables/tables.module.ts index 1b67ca8..2e5ebc7 100644 --- a/src/app/modules/shared/components/tables/tables.module.ts +++ b/src/app/modules/shared/components/tables/tables.module.ts @@ -4,6 +4,7 @@ import {CommonModule} from '@angular/common' import {CreInteractiveCell, CrePositionButtons, CreTable} from './tables' import {MatButtonModule} from "@angular/material/button"; import {MatIconModule} from "@angular/material/icon"; +import {MatSortModule} from '@angular/material/sort' @NgModule({ declarations: [ @@ -11,12 +12,13 @@ import {MatIconModule} from "@angular/material/icon"; CreInteractiveCell, CrePositionButtons ], - imports: [ - MatTableModule, - CommonModule, - MatButtonModule, - MatIconModule - ], + imports: [ + MatTableModule, + CommonModule, + MatButtonModule, + MatIconModule, + MatSortModule + ], exports: [ CreTable, CreInteractiveCell, diff --git a/src/app/modules/shared/components/tables/tables.ts b/src/app/modules/shared/components/tables/tables.ts index c555716..25e3394 100644 --- a/src/app/modules/shared/components/tables/tables.ts +++ b/src/app/modules/shared/components/tables/tables.ts @@ -2,14 +2,16 @@ import { AfterContentInit, Component, ContentChildren, - Directive, EventEmitter, + Directive, + EventEmitter, HostBinding, - Input, Output, + Input, + Output, QueryList, ViewChild, ViewEncapsulation } from '@angular/core' -import {MatColumnDef, MatHeaderRowDef, MatRowDef, MatTable} from '@angular/material/table' +import {MatColumnDef, MatHeaderRowDef, MatRowDef, MatTable, MatTableDataSource} from '@angular/material/table' @Directive({ selector: '[creInteractiveCell]' @@ -57,17 +59,32 @@ export class CreTable implements AfterContentInit { @ViewChild(MatTable, {static: true}) table: MatTable @Input() columns: string[] - @Input() dataSource: T[] @Input() interactive = true + @Input() filterFn: (t: T, string: string) => boolean = () => true + + @Input() set filter(filter: string) { + this.dataSource.filter = filter + } + + @Input() set data(data: T[]) { + this.setupDataSource(data) + } selectedIndex = 0 + dataSource: MatTableDataSource + ngAfterContentInit(): void { this.columnDefs.forEach(columnDef => this.table.addColumnDef(columnDef)) this.rowDefs.forEach(rowDef => this.table.addRowDef(rowDef)) this.headerRowDefs.forEach(headerRowDef => this.table.addHeaderRowDef(headerRowDef)) } + private setupDataSource(data: T[]) { + this.dataSource = new MatTableDataSource(data) + this.dataSource.filterPredicate = (t, filter) => this.filterFn(t, filter) + } + onRowHover(index: number) { if (this.interactive) { this.interactiveCells.forEach(cell => cell.hoverIndex = index) @@ -98,15 +115,15 @@ export class CrePositionButtons { @Input() disableDecreaseButton = false @Input() disableIncreaseButton = false - @Output() positionChange = new EventEmitter(); + @Output() positionChange = new EventEmitter() increasePosition() { - this.position += 1; + this.position += 1 this.positionChange.emit(this.position) } decreasePosition() { - this.position -= 1; + this.position -= 1 this.positionChange.emit(this.position) } } diff --git a/src/app/modules/shared/model/recipe.model.ts b/src/app/modules/shared/model/recipe.model.ts index a1bfeb5..7134171 100644 --- a/src/app/modules/shared/model/recipe.model.ts +++ b/src/app/modules/shared/model/recipe.model.ts @@ -124,3 +124,8 @@ export function getRecipeLuma(recipe: Recipe): number { return 0.2126 * r + 0.7152 * g + 0.0722 * b // per ITU-R BT.709 } + +export function recipeMatchesFilter(recipe: Recipe, filter: string): boolean { + const recipeStr = recipe.company.name + recipe.name + recipe.description + recipe.sample + return recipeStr.toLowerCase().indexOf(filter.toLowerCase()) >= 0 +} diff --git a/src/app/modules/touch-up-kit/pages/details.html b/src/app/modules/touch-up-kit/pages/details.html index bb5b358..93ebf4c 100644 --- a/src/app/modules/touch-up-kit/pages/details.html +++ b/src/app/modules/touch-up-kit/pages/details.html @@ -14,7 +14,7 @@ - + diff --git a/src/app/modules/touch-up-kit/pages/list.html b/src/app/modules/touch-up-kit/pages/list.html index 1cb372b..877aa6d 100644 --- a/src/app/modules/touch-up-kit/pages/list.html +++ b/src/app/modules/touch-up-kit/pages/list.html @@ -5,7 +5,7 @@ - + @@ -57,7 +57,7 @@ Kits de retouche complétés - + From a8d13cc1fb41f3e5b55ebf73950b7274ed6fd65c Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 1 Dec 2021 20:41:26 -0500 Subject: [PATCH 18/28] Start updating inventory --- src/app/modules/material/material.module.ts | 8 +- .../pages/inventory/inventory.component.html | 106 +++++++----------- .../pages/inventory/inventory.component.sass | 11 +- .../pages/inventory/inventory.component.ts | 34 ++++-- .../shared/components/tables/tables.ts | 17 ++- 5 files changed, 91 insertions(+), 85 deletions(-) diff --git a/src/app/modules/material/material.module.ts b/src/app/modules/material/material.module.ts index 2b934b2..d4f2fc2 100644 --- a/src/app/modules/material/material.module.ts +++ b/src/app/modules/material/material.module.ts @@ -9,6 +9,9 @@ import {EditComponent} from './pages/edit/edit.component'; import {RecipesModule} from '../recipes/recipes.module' import {MatSortModule} from '@angular/material/sort' import {FormsModule} from '@angular/forms' +import {CreTablesModule} from '../shared/components/tables/tables.module' +import {CreInputsModule} from '../shared/components/inputs/inputs.module' +import {CreButtonsModule} from '../shared/components/buttons/buttons.module' @NgModule({ @@ -19,7 +22,10 @@ import {FormsModule} from '@angular/forms' SharedModule, RecipesModule, MatSortModule, - FormsModule + FormsModule, + CreTablesModule, + CreInputsModule, + CreButtonsModule ] }) export class MaterialModule { diff --git a/src/app/modules/material/pages/inventory/inventory.component.html b/src/app/modules/material/pages/inventory/inventory.component.html index dd49bc1..aef4f3a 100644 --- a/src/app/modules/material/pages/inventory/inventory.component.html +++ b/src/app/modules/material/pages/inventory/inventory.component.html @@ -1,47 +1,34 @@
- - Recherche par code... - - - - Recherche par type de produit - - - {{materialType.name}} - - - + + + +
- - Quantité faible - - + + - +
@@ -51,19 +38,18 @@

-
Nom {{product.name}} Project {{touchUpKit.project}} Project {{touchUpKit.project}}
+ [data]="dataSource" + [columns]="columns"> - + - + @@ -75,9 +61,7 @@ + - - - - -
CodeCode {{material.name}} Type de produitType de produit {{material.materialType.name}} -
+
-
- - - + + Modifier + - - - + + Fiche signalitique +
+
diff --git a/src/app/modules/material/pages/inventory/inventory.component.sass b/src/app/modules/material/pages/inventory/inventory.component.sass index 20ded20..5867821 100644 --- a/src/app/modules/material/pages/inventory/inventory.component.sass +++ b/src/app/modules/material/pages/inventory/inventory.component.sass @@ -1,8 +1,9 @@ -.input-group-append button - border-radius: 0 4px 4px 0 - mat-select margin-top: 4px -.form-control - width: 6rem +.input-group + cre-input + width: 6rem + + .input-group-append button + border-radius: 0 4px 4px 0 diff --git a/src/app/modules/material/pages/inventory/inventory.component.ts b/src/app/modules/material/pages/inventory/inventory.component.ts index a6d8794..2c08589 100644 --- a/src/app/modules/material/pages/inventory/inventory.component.ts +++ b/src/app/modules/material/pages/inventory/inventory.component.ts @@ -12,6 +12,9 @@ import {MatTableDataSource} from '@angular/material/table' import {MaterialTypeService} from '../../../material-type/service/material-type.service' import {InventoryService} from '../../service/inventory.service' import {AppState} from '../../../shared/app-state' +import {FormControl} from '@angular/forms' +import {map} from 'rxjs/operators' +import {CreInputEntry} from '../../../shared/components/inputs/inputs' @Component({ selector: 'cre-list', @@ -22,7 +25,9 @@ export class InventoryComponent extends ErrorHandlingComponent { @ViewChild(MatSort) sort: MatSort materials: Material[] | null = [] - materialTypes$ = this.materialTypeService.all + materialTypesEntries$ = this.materialTypeService.all.pipe(map(materialTypes => { + return materialTypes.map(materialType => new CreInputEntry(materialType.id, materialType.name)) + })) dataSource: MatTableDataSource columns = ['name', 'materialType', 'quantity', 'addQuantity', 'lowQuantityIcon', 'simdutIcon', 'editButton', 'openSimdutButton'] @@ -31,8 +36,12 @@ export class InventoryComponent extends ErrorHandlingComponent { units = UNIT_MILLILITER lowQuantityThreshold = 100 // TEMPORARY will be in the application settings - materialTypeFilter = 1 - materialNameFilter = '' + + materialTypeFilterControl = new FormControl() + materialNameFilterControl = new FormControl() + + private materialTypeFilter = 1 + private materialNameFilter = '' constructor( private materialService: MaterialService, @@ -60,6 +69,16 @@ export class InventoryComponent extends ErrorHandlingComponent { true, 1 ) + + this.subscribe( + this.materialTypeFilterControl.valueChanges, + filter => this.materialTypeFilter = filter + ) + + this.subscribe( + this.materialNameFilterControl.valueChanges, + filter => this.materialNameFilter = filter + ) } setupDataSource(): MatTableDataSource { @@ -83,10 +102,6 @@ export class InventoryComponent extends ErrorHandlingComponent { return this.dataSource } - filterDataSource() { - this.dataSource.filter = 'filter' - } - isLowQuantity(material: Material) { return this.getQuantity(material) < this.lowQuantityThreshold } @@ -118,6 +133,11 @@ export class InventoryComponent extends ErrorHandlingComponent { ) } + get filter(): string { + // Uses private UTF-8 char to separate the two fields, change if a better method is found + return `${this.materialTypeFilter}􀃿${this.materialNameFilter}` + } + get canEditMaterial(): boolean { return this.accountService.hasPermission(Permission.EDIT_MATERIALS) } diff --git a/src/app/modules/shared/components/tables/tables.ts b/src/app/modules/shared/components/tables/tables.ts index 25e3394..6d4d7ca 100644 --- a/src/app/modules/shared/components/tables/tables.ts +++ b/src/app/modules/shared/components/tables/tables.ts @@ -13,6 +13,8 @@ import { } from '@angular/core' import {MatColumnDef, MatHeaderRowDef, MatRowDef, MatTable, MatTableDataSource} from '@angular/material/table' +type CreTableData = T[] | MatTableDataSource + @Directive({ selector: '[creInteractiveCell]' }) @@ -66,7 +68,7 @@ export class CreTable implements AfterContentInit { this.dataSource.filter = filter } - @Input() set data(data: T[]) { + @Input() set data(data: CreTableData) { this.setupDataSource(data) } @@ -80,9 +82,16 @@ export class CreTable implements AfterContentInit { this.headerRowDefs.forEach(headerRowDef => this.table.addHeaderRowDef(headerRowDef)) } - private setupDataSource(data: T[]) { - this.dataSource = new MatTableDataSource(data) - this.dataSource.filterPredicate = (t, filter) => this.filterFn(t, filter) + private setupDataSource(data: CreTableData) { + if (data instanceof MatTableDataSource) { + this.dataSource = data + } else { + this.dataSource = new MatTableDataSource(data) + } + + if (this.filterFn) { + this.dataSource.filterPredicate = (t, filter) => this.filterFn(t, filter) + } } onRowHover(index: number) { From 3a5f90b8c53b48ba982cd2c74b1cfdc7ee35f3c2 Mon Sep 17 00:00:00 2001 From: William Date: Wed, 1 Dec 2021 22:23:02 -0500 Subject: [PATCH 19/28] Low quantity filter --- .../pages/inventory/inventory.component.html | 14 +++-- .../pages/inventory/inventory.component.ts | 57 +++++++++---------- src/app/modules/recipes/list.html | 2 +- .../shared/components/tables/tables.ts | 7 ++- 4 files changed, 43 insertions(+), 37 deletions(-) diff --git a/src/app/modules/material/pages/inventory/inventory.component.html b/src/app/modules/material/pages/inventory/inventory.component.html index aef4f3a..8527e81 100644 --- a/src/app/modules/material/pages/inventory/inventory.component.html +++ b/src/app/modules/material/pages/inventory/inventory.component.html @@ -11,6 +11,10 @@ [control]="materialTypeFilterControl" [entries]="materialTypesEntries$"> + +
@@ -41,15 +45,17 @@ - Code + Code {{material.name}} - Type de produit + Type de produit {{material.materialType.name}} @@ -82,7 +88,7 @@ - + { return materialTypes.map(materialType => new CreInputEntry(materialType.id, materialType.name)) })) - dataSource: MatTableDataSource columns = ['name', 'materialType', 'quantity', 'addQuantity', 'lowQuantityIcon', 'simdutIcon', 'editButton', 'openSimdutButton'] hoveredMaterial: Material | null @@ -37,11 +35,31 @@ export class InventoryComponent extends ErrorHandlingComponent { units = UNIT_MILLILITER lowQuantityThreshold = 100 // TEMPORARY will be in the application settings - materialTypeFilterControl = new FormControl() - materialNameFilterControl = new FormControl() + materialFilterPredicate = (material: Material, filter: string): boolean => { + const [materialTypeFilter, materialNameFilter, hideLowQuantity, lowQuantityThreshold] = filter.split('􀃿') + const materialTypeId = parseInt(materialTypeFilter) + const lowQuantityThresholdInt = parseInt(lowQuantityThreshold) + const matchesMaterialType = materialTypeId === 1 || materialTypeId == material.materialType.id + const matchesMaterialName = !materialNameFilter || material.name.toLowerCase().includes(materialNameFilter.toLowerCase()) + const matchesLowQuantity = material.inventoryQuantity > lowQuantityThresholdInt + const matchesFilter = matchesMaterialType && matchesMaterialName + + if (!hideLowQuantity) { + // return matchesFilter || false + return false + } else { + // return material.inventoryQuantity > lowQuantityThresholdInt + return true + } + } private materialTypeFilter = 1 private materialNameFilter = '' + private hideLowQuantity = false + + materialTypeFilterControl = new FormControl(this.materialTypeFilter) + materialNameFilterControl = new FormControl(this.materialNameFilter) + hideLowQuantityControl = new FormControl(this.hideLowQuantity) constructor( private materialService: MaterialService, @@ -62,10 +80,7 @@ export class InventoryComponent extends ErrorHandlingComponent { this.subscribe( this.materialService.allNotMixType, - materials => { - this.materials = materials - this.dataSource = this.setupDataSource() - }, + materials => this.materials = materials, true, 1 ) @@ -79,27 +94,11 @@ export class InventoryComponent extends ErrorHandlingComponent { this.materialNameFilterControl.valueChanges, filter => this.materialNameFilter = filter ) - } - setupDataSource(): MatTableDataSource { - this.dataSource = new MatTableDataSource(this.materials) - this.dataSource.sortingDataAccessor = (material, header) => { - switch (header) { - case 'materialType': - return material[header].name - case 'lowQuantityIcon': - return this.isLowQuantity(material) - default: - return material[header] - } - } - this.dataSource.filterPredicate = (material, filter) => { - return (!this.materialTypeFilter || this.materialTypeFilter === 1 || material.materialType.id === this.materialTypeFilter) && - (!this.materialNameFilter || material.name.toLowerCase().includes(this.materialNameFilter.toLowerCase())) - } - - this.dataSource.sort = this.sort - return this.dataSource + this.subscribe( + this.hideLowQuantityControl.valueChanges, + filter => this.hideLowQuantity = filter + ) } isLowQuantity(material: Material) { @@ -135,7 +134,7 @@ export class InventoryComponent extends ErrorHandlingComponent { get filter(): string { // Uses private UTF-8 char to separate the two fields, change if a better method is found - return `${this.materialTypeFilter}􀃿${this.materialNameFilter}` + return `${this.materialTypeFilter}􀃿${this.materialNameFilter}􀃿${this.hideLowQuantity}􀃿${this.lowQuantityThreshold}` } get canEditMaterial(): boolean { diff --git a/src/app/modules/recipes/list.html b/src/app/modules/recipes/list.html index 81d7de1..37ed007 100644 --- a/src/app/modules/recipes/list.html +++ b/src/app/modules/recipes/list.html @@ -41,7 +41,7 @@ [columns]="columns" [data]="recipes" [filter]="searchQuery" - [filterFn]="recipeFilterPredicate"> + [filterPredicate]="recipeFilterPredicate"> Nom diff --git a/src/app/modules/shared/components/tables/tables.ts b/src/app/modules/shared/components/tables/tables.ts index 6d4d7ca..a326556 100644 --- a/src/app/modules/shared/components/tables/tables.ts +++ b/src/app/modules/shared/components/tables/tables.ts @@ -62,7 +62,8 @@ export class CreTable implements AfterContentInit { @Input() columns: string[] @Input() interactive = true - @Input() filterFn: (t: T, string: string) => boolean = () => true + @Input() filterPredicate: (t: T, filter: string) => boolean = () => true + @Input() sortingDataAccessor: (t: T, header: string) => string | number @Input() set filter(filter: string) { this.dataSource.filter = filter @@ -89,8 +90,8 @@ export class CreTable implements AfterContentInit { this.dataSource = new MatTableDataSource(data) } - if (this.filterFn) { - this.dataSource.filterPredicate = (t, filter) => this.filterFn(t, filter) + if (this.filterPredicate) { + this.dataSource.filterPredicate = (t, filter) => this.filterPredicate(t, filter) } } From e18fe04f3680d20fe35fa4981dd9f03e1097c24e Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 1 Dec 2021 22:52:00 -0500 Subject: [PATCH 20/28] Update inventory --- src/app/modules/material/material.module.ts | 4 ++- .../pages/inventory/inventory.component.html | 16 +++++------- .../pages/inventory/inventory.component.ts | 26 ++++--------------- .../shared/components/tables/tables.ts | 16 +++++------- .../modules/shared/model/material.model.ts | 15 ++++++++++- src/app/modules/shared/utils/utils.ts | 5 ++++ 6 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/app/modules/material/material.module.ts b/src/app/modules/material/material.module.ts index d4f2fc2..782b3ef 100644 --- a/src/app/modules/material/material.module.ts +++ b/src/app/modules/material/material.module.ts @@ -12,6 +12,7 @@ import {FormsModule} from '@angular/forms' import {CreTablesModule} from '../shared/components/tables/tables.module' import {CreInputsModule} from '../shared/components/inputs/inputs.module' import {CreButtonsModule} from '../shared/components/buttons/buttons.module' +import {CreActionBarModule} from '../shared/components/action-bar/action-bar.module' @NgModule({ @@ -25,7 +26,8 @@ import {CreButtonsModule} from '../shared/components/buttons/buttons.module' FormsModule, CreTablesModule, CreInputsModule, - CreButtonsModule + CreButtonsModule, + CreActionBarModule ] }) export class MaterialModule { diff --git a/src/app/modules/material/pages/inventory/inventory.component.html b/src/app/modules/material/pages/inventory/inventory.component.html index 8527e81..130ff57 100644 --- a/src/app/modules/material/pages/inventory/inventory.component.html +++ b/src/app/modules/material/pages/inventory/inventory.component.html @@ -1,12 +1,12 @@ -
- -
+ + @@ -15,10 +15,8 @@ label="Basse quantité" [control]="hideLowQuantityControl"> -
- - -
+ + Ajouter -
-
+ +

Il n'y a actuellement aucun produit enregistré dans le système.

diff --git a/src/app/modules/material/pages/inventory/inventory.component.ts b/src/app/modules/material/pages/inventory/inventory.component.ts index 0309f75..81f914f 100644 --- a/src/app/modules/material/pages/inventory/inventory.component.ts +++ b/src/app/modules/material/pages/inventory/inventory.component.ts @@ -4,7 +4,7 @@ import {MaterialService} from '../../service/material.service' import {Permission} from '../../../shared/model/user' import {ActivatedRoute, Router} from '@angular/router' import {ErrorService} from '../../../shared/service/error.service' -import {Material, openSimdut} from '../../../shared/model/material.model' +import {Material, materialFilterFieldSeparator, materialMatchesFilter, openSimdut} from '../../../shared/model/material.model' import {AccountService} from '../../../accounts/services/account.service' import {convertQuantity, UNIT_MILLILITER} from '../../../shared/units' import {MatSort} from '@angular/material/sort' @@ -14,6 +14,7 @@ import {AppState} from '../../../shared/app-state' import {FormControl} from '@angular/forms' import {map} from 'rxjs/operators' import {CreInputEntry} from '../../../shared/components/inputs/inputs' +import {round} from '../../../shared/utils/utils' @Component({ selector: 'cre-list', @@ -35,23 +36,7 @@ export class InventoryComponent extends ErrorHandlingComponent { units = UNIT_MILLILITER lowQuantityThreshold = 100 // TEMPORARY will be in the application settings - materialFilterPredicate = (material: Material, filter: string): boolean => { - const [materialTypeFilter, materialNameFilter, hideLowQuantity, lowQuantityThreshold] = filter.split('􀃿') - const materialTypeId = parseInt(materialTypeFilter) - const lowQuantityThresholdInt = parseInt(lowQuantityThreshold) - const matchesMaterialType = materialTypeId === 1 || materialTypeId == material.materialType.id - const matchesMaterialName = !materialNameFilter || material.name.toLowerCase().includes(materialNameFilter.toLowerCase()) - const matchesLowQuantity = material.inventoryQuantity > lowQuantityThresholdInt - const matchesFilter = matchesMaterialType && matchesMaterialName - - if (!hideLowQuantity) { - // return matchesFilter || false - return false - } else { - // return material.inventoryQuantity > lowQuantityThresholdInt - return true - } - } + materialFilterPredicate = materialMatchesFilter private materialTypeFilter = 1 private materialNameFilter = '' @@ -106,7 +91,7 @@ export class InventoryComponent extends ErrorHandlingComponent { } getQuantity(material: Material): number { - return Math.round(convertQuantity(material.inventoryQuantity, UNIT_MILLILITER, this.units) * 100) / 100 + return round(convertQuantity(material.inventoryQuantity, UNIT_MILLILITER, this.units), 2) } materialHasSimdut(material: Material): boolean { @@ -133,8 +118,7 @@ export class InventoryComponent extends ErrorHandlingComponent { } get filter(): string { - // Uses private UTF-8 char to separate the two fields, change if a better method is found - return `${this.materialTypeFilter}􀃿${this.materialNameFilter}􀃿${this.hideLowQuantity}􀃿${this.lowQuantityThreshold}` + return [this.materialTypeFilter, this.materialNameFilter, this.hideLowQuantity, this.lowQuantityThreshold].join(materialFilterFieldSeparator) } get canEditMaterial(): boolean { diff --git a/src/app/modules/shared/components/tables/tables.ts b/src/app/modules/shared/components/tables/tables.ts index a326556..a7e7d5d 100644 --- a/src/app/modules/shared/components/tables/tables.ts +++ b/src/app/modules/shared/components/tables/tables.ts @@ -13,8 +13,6 @@ import { } from '@angular/core' import {MatColumnDef, MatHeaderRowDef, MatRowDef, MatTable, MatTableDataSource} from '@angular/material/table' -type CreTableData = T[] | MatTableDataSource - @Directive({ selector: '[creInteractiveCell]' }) @@ -66,10 +64,12 @@ export class CreTable implements AfterContentInit { @Input() sortingDataAccessor: (t: T, header: string) => string | number @Input() set filter(filter: string) { - this.dataSource.filter = filter + if (this.dataSource) { + this.dataSource.filter = filter + } } - @Input() set data(data: CreTableData) { + @Input() set data(data: T[]) { this.setupDataSource(data) } @@ -83,12 +83,8 @@ export class CreTable implements AfterContentInit { this.headerRowDefs.forEach(headerRowDef => this.table.addHeaderRowDef(headerRowDef)) } - private setupDataSource(data: CreTableData) { - if (data instanceof MatTableDataSource) { - this.dataSource = data - } else { - this.dataSource = new MatTableDataSource(data) - } + private setupDataSource(data: T[]) { + this.dataSource = new MatTableDataSource(data) if (this.filterPredicate) { this.dataSource.filterPredicate = (t, filter) => this.filterPredicate(t, filter) diff --git a/src/app/modules/shared/model/material.model.ts b/src/app/modules/shared/model/material.model.ts index 5c31599..681e1f6 100644 --- a/src/app/modules/shared/model/material.model.ts +++ b/src/app/modules/shared/model/material.model.ts @@ -1,4 +1,4 @@ -import {MaterialType} from './materialtype.model'; +import {MaterialType} from './materialtype.model' import {openPdf} from '../utils/utils' export class Material { @@ -37,3 +37,16 @@ export const materialComparator = (a: Material, b: Material): number => { } } } + +// Uses private use UTF-8 char to separate the two fields, change if a better method is found +export const materialFilterFieldSeparator = '􀃿' + +export function materialMatchesFilter(material: Material, filter: string): boolean { + const [materialTypeFilter, materialNameFilter, hideLowQuantity, lowQuantityThreshold] = filter.split(materialFilterFieldSeparator) + const materialTypeId = parseInt(materialTypeFilter) + const matchesMaterialType = materialTypeId === 1 || materialTypeId == material.materialType.id + const matchesMaterialName = !materialNameFilter || material.name.toLowerCase().includes(materialNameFilter.toLowerCase()) + const matchesLowQuantity = material.inventoryQuantity < parseInt(lowQuantityThreshold) + + return matchesMaterialType && matchesMaterialName && (hideLowQuantity === 'false' || matchesLowQuantity) +} diff --git a/src/app/modules/shared/utils/utils.ts b/src/app/modules/shared/utils/utils.ts index 316a49c..929c0c9 100644 --- a/src/app/modules/shared/utils/utils.ts +++ b/src/app/modules/shared/utils/utils.ts @@ -64,3 +64,8 @@ export function getFileUrl(path: string) { export function getConfiguredImageUrl(path: string) { return `${environment.apiUrl}/config/${path}` } + +export function round(n: number, digits: number): number { + const power = Math.pow(10, digits) + return Math.round(n * power) / power +} From 75f356cc5a190fa802de879ef879a9908c898a2b Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 1 Dec 2021 23:03:24 -0500 Subject: [PATCH 21/28] Update to Angular 12 --- angular.json | 12 +++++++++--- package.json | 30 +++++++++++++++--------------- src/environments/environment.ts | 2 +- src/polyfills.ts | 2 +- src/test.ts | 2 +- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/angular.json b/angular.json index bf30028..2fab785 100644 --- a/angular.json +++ b/angular.json @@ -22,7 +22,6 @@ "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", - "aot": true, "assets": [ "src/favicon.ico", "src/assets", @@ -37,7 +36,13 @@ "src/custom-theme.scss", "src/styles.sass" ], - "scripts": [] + "scripts": [], + "vendorChunk": true, + "extractLicenses": false, + "buildOptimizer": false, + "sourceMap": true, + "optimization": false, + "namedChunks": true }, "configurations": { "production": { @@ -67,7 +72,8 @@ } ] } - } + }, + "defaultConfiguration": "" }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", diff --git a/package.json b/package.json index c0d8071..00afd41 100644 --- a/package.json +++ b/package.json @@ -11,16 +11,16 @@ }, "private": true, "dependencies": { - "@angular/animations": "~11.2.10", + "@angular/animations": "~12.2.14", "@angular/cdk": "^11.2.11", - "@angular/common": "~11.2.10", - "@angular/compiler": "~11.2.10", - "@angular/core": "~11.2.10", - "@angular/forms": "~11.2.10", + "@angular/common": "~12.2.14", + "@angular/compiler": "~12.2.14", + "@angular/core": "~12.2.14", + "@angular/forms": "~12.2.14", "@angular/material": "^11.2.9", - "@angular/platform-browser": "~11.2.10", - "@angular/platform-browser-dynamic": "~11.2.10", - "@angular/router": "~11.2.10", + "@angular/platform-browser": "~12.2.14", + "@angular/platform-browser-dynamic": "~12.2.14", + "@angular/router": "~12.2.14", "@mdi/angular-material": "^5.7.55", "bootstrap": "^4.5.2", "copy-webpack-plugin": "^6.2.1", @@ -29,18 +29,18 @@ "ngx-material-file-input": "^2.1.1", "rxjs": "~6.5.4", "tslib": "^2.0.0", - "zone.js": "~0.10.2" + "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "^0.1102.9", + "@angular-devkit/build-angular": "^12.2.13", "@angular-eslint/builder": "4.3.0", "@angular-eslint/eslint-plugin": "4.3.0", "@angular-eslint/eslint-plugin-template": "4.3.0", "@angular-eslint/schematics": "4.3.0", "@angular-eslint/template-parser": "4.3.0", - "@angular/cli": "^11.2.11", - "@angular/compiler-cli": "~11.2.10", - "@angular/language-service": "~11.2.10", + "@angular/cli": "^12.2.13", + "@angular/compiler-cli": "~12.2.14", + "@angular/language-service": "~12.2.14", "@types/jasmine": "~3.6.0", "@types/jasminewd2": "~2.0.3", "@types/node": "^12.11.1", @@ -59,6 +59,6 @@ "karma-jasmine-html-reporter": "^1.5.0", "protractor": "~7.0.0", "ts-node": "~8.3.0", - "typescript": "~4.0.7" + "typescript": "~4.3.5" } -} +} \ No newline at end of file diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 07d5091..8a40323 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -14,4 +14,4 @@ export const environment = { * This import should be commented out in production mode because it will have a negative impact * on performance if an error is thrown. */ -// import 'zone.js/dist/zone-error'; // Included with Angular CLI. +// import 'zone.js/plugins/zone-error'; // Included with Angular CLI. diff --git a/src/polyfills.ts b/src/polyfills.ts index 03711e5..67581db 100644 --- a/src/polyfills.ts +++ b/src/polyfills.ts @@ -55,7 +55,7 @@ /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. +import 'zone.js'; // Included with Angular CLI. /*************************************************************************************************** diff --git a/src/test.ts b/src/test.ts index 50193eb..2042356 100644 --- a/src/test.ts +++ b/src/test.ts @@ -1,6 +1,6 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/dist/zone-testing'; +import 'zone.js/testing'; import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, From f37363e457945267d91cac6fbb86a927a597ba74 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 1 Dec 2021 23:12:23 -0500 Subject: [PATCH 22/28] Update to Angular Material 12 --- package.json | 4 ++-- src/_variables.scss | 3 +++ src/custom-theme.scss | 18 +++++++++--------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 00afd41..775fa71 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,12 @@ "private": true, "dependencies": { "@angular/animations": "~12.2.14", - "@angular/cdk": "^11.2.11", + "@angular/cdk": "^12.2.13", "@angular/common": "~12.2.14", "@angular/compiler": "~12.2.14", "@angular/core": "~12.2.14", "@angular/forms": "~12.2.14", - "@angular/material": "^11.2.9", + "@angular/material": "^12.2.13", "@angular/platform-browser": "~12.2.14", "@angular/platform-browser-dynamic": "~12.2.14", "@angular/router": "~12.2.14", diff --git a/src/_variables.scss b/src/_variables.scss index 4ff7528..85f90d1 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -18,3 +18,6 @@ $text-color-primary: white; $color-accent: map-get($theme-accent, 500); $color-warn: map-get($theme-error, 500); + +$light-primary-text: white; +$dark-secondary-text: black; diff --git a/src/custom-theme.scss b/src/custom-theme.scss index 5f766ef..cd65d4e 100644 --- a/src/custom-theme.scss +++ b/src/custom-theme.scss @@ -1,21 +1,21 @@ // Custom Theming for Angular Material +@use '~@angular/material' as mat; // For more information: https://material.angular.io/guide/theming -@import '~@angular/material/theming'; // Plus imports for other components in your app. -$custom-typography: mat-typography-config( +$custom-typography: mat.define-typography-config( $font-family: "Open Sans" ); // Include the common styles for Angular Material. We include this here so that you only // have to load a single css file for Angular Material in your app. // Be sure that you only ever include this mixin once! -@include mat-core($custom-typography); +@include mat.core($custom-typography); // Define the palettes for your theme using the Material Design palettes available in palette.sass // (imported above). For each palette, you can optionally specify a default, lighter, and darker // hue. Available color palettes: https://material.io/design/color/ -$theme-primary: mat-palette(( +$theme-primary: mat.define-palette(( 50 : #e0e0e0, 100 : #b3b3b3, 200 : #808080, @@ -46,7 +46,7 @@ $theme-primary: mat-palette(( A400 : #ffffff, A700 : #ffffff, ))); -$theme-accent: mat-palette(( +$theme-accent: mat.define-palette(( 50 : #edf9e0, 100 : #d1f0b3, 200 : #b3e680, @@ -78,7 +78,7 @@ $theme-accent: mat-palette(( A700 : #000000, ) )); -$theme-warning: mat-palette(( +$theme-warning: mat.define-palette(( 50 : #fff8e4, 100 : #feefbd, 200 : #fee491, @@ -112,15 +112,15 @@ $theme-warning: mat-palette(( )); // The warn palette is optional (defaults to red). -$theme-error: mat-palette($mat-red); +$theme-error: mat.define-palette(mat.$red-palette); // Create the theme object (a Sass map containing all of the palettes). -$color-recipes-explorer-frontend-theme: mat-light-theme($theme-primary, $theme-accent, $theme-error); +$color-recipes-explorer-frontend-theme: mat.define-light-theme($theme-primary, $theme-accent, $theme-error); // Include theme styles for core and each component used in your app. // Alternatively, you can import and @include the theme mixins for each component // that you are using. -@include angular-material-theme($color-recipes-explorer-frontend-theme); +@include mat.all-component-themes($color-recipes-explorer-frontend-theme); html, body { From 5b564460d47a1b9b772d85156d637109bdf7990e Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 1 Dec 2021 23:13:48 -0500 Subject: [PATCH 23/28] Setup update to Angular 13 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 775fa71..2e40cdd 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "copy-webpack-plugin": "^6.2.1", "js-joda": "^1.11.0", "material-design-icons": "^3.0.1", - "ngx-material-file-input": "^2.1.1", + "ngx-material-file-input": "3.0.0", "rxjs": "~6.5.4", "tslib": "^2.0.0", "zone.js": "~0.11.4" @@ -61,4 +61,4 @@ "ts-node": "~8.3.0", "typescript": "~4.3.5" } -} \ No newline at end of file +} From f644edae21c287e40f2acd163a55c43e2ac9d468 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 1 Dec 2021 23:15:51 -0500 Subject: [PATCH 24/28] Setup update to Angular 13 --- package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 2e40cdd..060c202 100644 --- a/package.json +++ b/package.json @@ -33,20 +33,20 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^12.2.13", - "@angular-eslint/builder": "4.3.0", - "@angular-eslint/eslint-plugin": "4.3.0", - "@angular-eslint/eslint-plugin-template": "4.3.0", - "@angular-eslint/schematics": "4.3.0", - "@angular-eslint/template-parser": "4.3.0", + "@angular-eslint/builder": "13.0.1", + "@angular-eslint/eslint-plugin": "13.0.1", + "@angular-eslint/eslint-plugin-template": "13.0.1", + "@angular-eslint/schematics": "13.0.1", + "@angular-eslint/template-parser": "13.0.1", "@angular/cli": "^12.2.13", "@angular/compiler-cli": "~12.2.14", "@angular/language-service": "~12.2.14", "@types/jasmine": "~3.6.0", "@types/jasminewd2": "~2.0.3", "@types/node": "^12.11.1", - "@typescript-eslint/eslint-plugin": "4.16.1", - "@typescript-eslint/parser": "4.16.1", - "eslint": "^7.6.0", + "@typescript-eslint/eslint-plugin": "5.5.0", + "@typescript-eslint/parser": "5.5.0", + "eslint": "8.3.0", "eslint-plugin-import": "latest", "eslint-plugin-jsdoc": "latest", "eslint-plugin-prefer-arrow": "latest", From 3136f2e1d65cfef12af92653aa5baac38c053436 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 1 Dec 2021 23:19:35 -0500 Subject: [PATCH 25/28] Update to Angular 13 --- .gitignore | 1 + package.json | 28 ++++++++++++++-------------- src/polyfills.ts | 10 ---------- src/test.ts | 4 +++- 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 2e789dc..ccbebdb 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ speed-measure-plugin*.json .history/* # misc +/.angular/cache /.sass-cache /connect.lock /coverage diff --git a/package.json b/package.json index 060c202..77be7b3 100644 --- a/package.json +++ b/package.json @@ -11,16 +11,16 @@ }, "private": true, "dependencies": { - "@angular/animations": "~12.2.14", + "@angular/animations": "~13.0.3", "@angular/cdk": "^12.2.13", - "@angular/common": "~12.2.14", - "@angular/compiler": "~12.2.14", - "@angular/core": "~12.2.14", - "@angular/forms": "~12.2.14", + "@angular/common": "~13.0.3", + "@angular/compiler": "~13.0.3", + "@angular/core": "~13.0.3", + "@angular/forms": "~13.0.3", "@angular/material": "^12.2.13", - "@angular/platform-browser": "~12.2.14", - "@angular/platform-browser-dynamic": "~12.2.14", - "@angular/router": "~12.2.14", + "@angular/platform-browser": "~13.0.3", + "@angular/platform-browser-dynamic": "~13.0.3", + "@angular/router": "~13.0.3", "@mdi/angular-material": "^5.7.55", "bootstrap": "^4.5.2", "copy-webpack-plugin": "^6.2.1", @@ -32,15 +32,15 @@ "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "^12.2.13", + "@angular-devkit/build-angular": "^13.0.4", "@angular-eslint/builder": "13.0.1", "@angular-eslint/eslint-plugin": "13.0.1", "@angular-eslint/eslint-plugin-template": "13.0.1", "@angular-eslint/schematics": "13.0.1", "@angular-eslint/template-parser": "13.0.1", - "@angular/cli": "^12.2.13", - "@angular/compiler-cli": "~12.2.14", - "@angular/language-service": "~12.2.14", + "@angular/cli": "^13.0.4", + "@angular/compiler-cli": "~13.0.3", + "@angular/language-service": "~13.0.3", "@types/jasmine": "~3.6.0", "@types/jasminewd2": "~2.0.3", "@types/node": "^12.11.1", @@ -59,6 +59,6 @@ "karma-jasmine-html-reporter": "^1.5.0", "protractor": "~7.0.0", "ts-node": "~8.3.0", - "typescript": "~4.3.5" + "typescript": "~4.4.4" } -} +} \ No newline at end of file diff --git a/src/polyfills.ts b/src/polyfills.ts index 67581db..dcd18ea 100644 --- a/src/polyfills.ts +++ b/src/polyfills.ts @@ -18,16 +18,6 @@ * BROWSER POLYFILLS */ -/** IE10 and IE11 requires the following for NgClass support on SVG elements */ -// import 'classlist.js'; // Run `npm install --save classlist.js`. - -/** - * Web Animations `@angular/platform-browser/animations` - * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. - * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). - */ -// import 'web-animations-js'; // Run `npm install --save web-animations-js`. - /** * By default, zone.js will patch all possible macroTask and DomEvents * user can disable parts of macroTask/DomEvents patch by setting following flags diff --git a/src/test.ts b/src/test.ts index 2042356..4bf4afb 100644 --- a/src/test.ts +++ b/src/test.ts @@ -17,7 +17,9 @@ declare const require: { // First, initialize the Angular testing environment. getTestBed().initTestEnvironment( BrowserDynamicTestingModule, - platformBrowserDynamicTesting() + platformBrowserDynamicTesting(), { + teardown: { destroyAfterEach: false } +} ); // Then we find all the tests. const context = require.context('./', true, /\.spec\.ts$/); From 6ba107300488dba5d08fd4e34266070b6abeae7c Mon Sep 17 00:00:00 2001 From: FyloZ Date: Thu, 2 Dec 2021 13:58:29 -0500 Subject: [PATCH 26/28] Update to Angular 13 --- angular.json | 2 +- package.json | 36 ++++++++++++++++++------------------ src/_variables.scss | 1 + src/custom-theme.scss | 2 +- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/angular.json b/angular.json index 2fab785..fb6d6d1 100644 --- a/angular.json +++ b/angular.json @@ -40,7 +40,7 @@ "vendorChunk": true, "extractLicenses": false, "buildOptimizer": false, - "sourceMap": true, + "sourceMap": false, "optimization": false, "namedChunks": true }, diff --git a/package.json b/package.json index 77be7b3..375332c 100644 --- a/package.json +++ b/package.json @@ -12,24 +12,24 @@ "private": true, "dependencies": { "@angular/animations": "~13.0.3", - "@angular/cdk": "^12.2.13", + "@angular/cdk": "^13.0.3", "@angular/common": "~13.0.3", "@angular/compiler": "~13.0.3", "@angular/core": "~13.0.3", "@angular/forms": "~13.0.3", - "@angular/material": "^12.2.13", + "@angular/material": "^13.0.3", "@angular/platform-browser": "~13.0.3", "@angular/platform-browser-dynamic": "~13.0.3", "@angular/router": "~13.0.3", - "@mdi/angular-material": "^5.7.55", + "@mdi/angular-material": "^6.5.95", "bootstrap": "^4.5.2", - "copy-webpack-plugin": "^6.2.1", + "copy-webpack-plugin": "^10.0.0", "js-joda": "^1.11.0", "material-design-icons": "^3.0.1", "ngx-material-file-input": "3.0.0", - "rxjs": "~6.5.4", - "tslib": "^2.0.0", - "zone.js": "~0.11.4" + "rxjs": "^7.4.0", + "tslib": "^2.3.1", + "zone.js": "^0.11.4" }, "devDependencies": { "@angular-devkit/build-angular": "^13.0.4", @@ -41,24 +41,24 @@ "@angular/cli": "^13.0.4", "@angular/compiler-cli": "~13.0.3", "@angular/language-service": "~13.0.3", - "@types/jasmine": "~3.6.0", - "@types/jasminewd2": "~2.0.3", - "@types/node": "^12.11.1", + "@types/jasmine": "~3.10.2", + "@types/jasminewd2": "~2.0.10", + "@types/node": "^16.11.11", "@typescript-eslint/eslint-plugin": "5.5.0", "@typescript-eslint/parser": "5.5.0", "eslint": "8.3.0", "eslint-plugin-import": "latest", "eslint-plugin-jsdoc": "latest", "eslint-plugin-prefer-arrow": "latest", - "jasmine-core": "~3.6.0", - "jasmine-spec-reporter": "~5.0.0", - "karma": "~6.3.2", + "jasmine-core": "~3.10.1", + "jasmine-spec-reporter": "~7.0.0", + "karma": "~6.3.9", "karma-chrome-launcher": "~3.1.0", - "karma-coverage-istanbul-reporter": "~3.0.2", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", + "karma-coverage-istanbul-reporter": "~3.0.3", + "karma-jasmine": "~4.0.1", + "karma-jasmine-html-reporter": "^1.7.0", "protractor": "~7.0.0", - "ts-node": "~8.3.0", + "ts-node": "~10.4.0", "typescript": "~4.4.4" } -} \ No newline at end of file +} diff --git a/src/_variables.scss b/src/_variables.scss index 85f90d1..c616181 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -20,4 +20,5 @@ $color-accent: map-get($theme-accent, 500); $color-warn: map-get($theme-error, 500); $light-primary-text: white; +$dark-primary-text: black; $dark-secondary-text: black; diff --git a/src/custom-theme.scss b/src/custom-theme.scss index cd65d4e..cc4d450 100644 --- a/src/custom-theme.scss +++ b/src/custom-theme.scss @@ -1,5 +1,5 @@ // Custom Theming for Angular Material -@use '~@angular/material' as mat; +@use '@angular/material' as mat; // For more information: https://material.angular.io/guide/theming // Plus imports for other components in your app. From 2351ecd2582cd2eb911d320b7906d66389f01303 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Thu, 2 Dec 2021 14:07:15 -0500 Subject: [PATCH 27/28] Update to Angular 13 --- package.json | 2 +- src/app/modules/shared/utils/utils.ts | 2 +- src/app/modules/touch-up-kit/components/finish.sass | 2 +- src/app/modules/touch-up-kit/pages/touchupkit.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 375332c..19fd767 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "@mdi/angular-material": "^6.5.95", "bootstrap": "^4.5.2", "copy-webpack-plugin": "^10.0.0", - "js-joda": "^1.11.0", + "@js-joda/core": "^4.3.1", "material-design-icons": "^3.0.1", "ngx-material-file-input": "3.0.0", "rxjs": "^7.4.0", diff --git a/src/app/modules/shared/utils/utils.ts b/src/app/modules/shared/utils/utils.ts index 929c0c9..dfa6bf9 100644 --- a/src/app/modules/shared/utils/utils.ts +++ b/src/app/modules/shared/utils/utils.ts @@ -1,5 +1,5 @@ /** Returns [value] if it is not null or [or]. */ -import {DateTimeFormatter, LocalDate, LocalDateTime} from 'js-joda' +import {DateTimeFormatter, LocalDate, LocalDateTime} from '@js-joda/core' import {TouchUpKit} from '../model/touch-up-kit.model' import {environment} from '../../../../environments/environment' diff --git a/src/app/modules/touch-up-kit/components/finish.sass b/src/app/modules/touch-up-kit/components/finish.sass index 30c9991..7713c99 100644 --- a/src/app/modules/touch-up-kit/components/finish.sass +++ b/src/app/modules/touch-up-kit/components/finish.sass @@ -1,4 +1,4 @@ -@import '../../../../custom-theme' +@import '~src/variables' .touchupkit-finish-container display: inline-block diff --git a/src/app/modules/touch-up-kit/pages/touchupkit.ts b/src/app/modules/touch-up-kit/pages/touchupkit.ts index b9db2e4..4b661b7 100644 --- a/src/app/modules/touch-up-kit/pages/touchupkit.ts +++ b/src/app/modules/touch-up-kit/pages/touchupkit.ts @@ -10,9 +10,9 @@ import {Permission} from '../../shared/model/user' import {RecipeService} from '../../recipes/services/recipe.service' import {AppState} from '../../shared/app-state' import {map} from 'rxjs/operators' -import {LocalDate, Period} from 'js-joda' import {ConfigService} from '../../shared/service/config.service' import {Config} from '../../shared/model/config.model' +import {LocalDate, Period} from '@js-joda/core' @Component({ selector: 'touchupkit-banner', From b6f687e0f1cc4449f70d40dbf38287ad5cb00151 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Thu, 2 Dec 2021 14:36:55 -0500 Subject: [PATCH 28/28] Downgrade to Angular 12 --- package.json | 70 +++++++++---------- .../modules/touch-up-kit/pages/touchupkit.ts | 2 +- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 19fd767..b93082c 100644 --- a/package.json +++ b/package.json @@ -11,54 +11,54 @@ }, "private": true, "dependencies": { - "@angular/animations": "~13.0.3", - "@angular/cdk": "^13.0.3", - "@angular/common": "~13.0.3", - "@angular/compiler": "~13.0.3", - "@angular/core": "~13.0.3", - "@angular/forms": "~13.0.3", - "@angular/material": "^13.0.3", - "@angular/platform-browser": "~13.0.3", - "@angular/platform-browser-dynamic": "~13.0.3", - "@angular/router": "~13.0.3", + "@angular/animations": "~12.2.14", + "@angular/cdk": "^12.2.13", + "@angular/common": "~12.2.14", + "@angular/compiler": "~12.2.14", + "@angular/core": "~12.2.14", + "@angular/forms": "~12.2.14", + "@angular/material": "^12.2.13", + "@angular/platform-browser": "~12.2.14", + "@angular/platform-browser-dynamic": "~12.2.14", + "@angular/router": "~12.2.14", "@mdi/angular-material": "^6.5.95", "bootstrap": "^4.5.2", "copy-webpack-plugin": "^10.0.0", "@js-joda/core": "^4.3.1", "material-design-icons": "^3.0.1", - "ngx-material-file-input": "3.0.0", + "ngx-material-file-input": "^2.1.1", "rxjs": "^7.4.0", "tslib": "^2.3.1", - "zone.js": "^0.11.4" + "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "^13.0.4", - "@angular-eslint/builder": "13.0.1", - "@angular-eslint/eslint-plugin": "13.0.1", - "@angular-eslint/eslint-plugin-template": "13.0.1", - "@angular-eslint/schematics": "13.0.1", - "@angular-eslint/template-parser": "13.0.1", - "@angular/cli": "^13.0.4", - "@angular/compiler-cli": "~13.0.3", - "@angular/language-service": "~13.0.3", - "@types/jasmine": "~3.10.2", - "@types/jasminewd2": "~2.0.10", - "@types/node": "^16.11.11", - "@typescript-eslint/eslint-plugin": "5.5.0", - "@typescript-eslint/parser": "5.5.0", - "eslint": "8.3.0", + "@angular-devkit/build-angular": "^12.2.13", + "@angular-eslint/builder": "4.3.0", + "@angular-eslint/eslint-plugin": "4.3.0", + "@angular-eslint/eslint-plugin-template": "4.3.0", + "@angular-eslint/schematics": "4.3.0", + "@angular-eslint/template-parser": "4.3.0", + "@angular/cli": "^12.2.13", + "@angular/compiler-cli": "~12.2.14", + "@angular/language-service": "~12.2.14", + "@types/jasmine": "~3.6.0", + "@types/jasminewd2": "~2.0.3", + "@types/node": "^12.11.1", + "@typescript-eslint/eslint-plugin": "4.16.1", + "@typescript-eslint/parser": "4.16.1", + "eslint": "^8.3.0", "eslint-plugin-import": "latest", "eslint-plugin-jsdoc": "latest", "eslint-plugin-prefer-arrow": "latest", - "jasmine-core": "~3.10.1", - "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.3.9", + "jasmine-core": "^3.10.1", + "jasmine-spec-reporter": "^7.0.0", + "karma": "~6.3.2", "karma-chrome-launcher": "~3.1.0", - "karma-coverage-istanbul-reporter": "~3.0.3", - "karma-jasmine": "~4.0.1", - "karma-jasmine-html-reporter": "^1.7.0", + "karma-coverage-istanbul-reporter": "~3.0.2", + "karma-jasmine": "~4.0.0", + "karma-jasmine-html-reporter": "^1.5.0", "protractor": "~7.0.0", - "ts-node": "~10.4.0", - "typescript": "~4.4.4" + "ts-node": "^10.4.0", + "typescript": "~4.3.5" } } diff --git a/src/app/modules/touch-up-kit/pages/touchupkit.ts b/src/app/modules/touch-up-kit/pages/touchupkit.ts index 4b661b7..2cdf146 100644 --- a/src/app/modules/touch-up-kit/pages/touchupkit.ts +++ b/src/app/modules/touch-up-kit/pages/touchupkit.ts @@ -10,9 +10,9 @@ import {Permission} from '../../shared/model/user' import {RecipeService} from '../../recipes/services/recipe.service' import {AppState} from '../../shared/app-state' import {map} from 'rxjs/operators' +import {LocalDate, Period} from '@js-joda/core' import {ConfigService} from '../../shared/service/config.service' import {Config} from '../../shared/model/config.model' -import {LocalDate, Period} from '@js-joda/core' @Component({ selector: 'touchupkit-banner',