#14 Add messages when adding recipe
This commit is contained in:
parent
73bb2c3bce
commit
c35635c596
|
@ -7,7 +7,7 @@ import {CreConfigEditor} from './modules/configuration/config-editor'
|
||||||
|
|
||||||
const routes: Routes = [{
|
const routes: Routes = [{
|
||||||
path: 'color',
|
path: 'color',
|
||||||
loadChildren: () => import('./modules/colors/colors.module').then(m => m.ColorsModule)
|
loadChildren: () => import('./modules/recipes/recipes.module').then(m => m.RecipesModule)
|
||||||
}, {
|
}, {
|
||||||
path: 'account',
|
path: 'account',
|
||||||
loadChildren: () => import('./modules/accounts/accounts.module').then(m => m.AccountsModule)
|
loadChildren: () => import('./modules/accounts/accounts.module').then(m => m.AccountsModule)
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
<cre-entity-add
|
|
||||||
title="Création d'une recette"
|
|
||||||
backButtonLink="/color/list"
|
|
||||||
[formFields]="formFields"
|
|
||||||
(submit)="submit($event)">
|
|
||||||
</cre-entity-add>
|
|
|
@ -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}`)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<Recipe[]> {
|
|
||||||
return this.api.get<Recipe[]>('/recipe')
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllByName(name: string): Observable<Recipe[]> {
|
|
||||||
return this.api.get<Recipe[]>(`/recipe?name=${name}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
get allByCompany(): Observable<Map<number, Recipe[]>> {
|
|
||||||
return this.all.pipe(map(recipes => {
|
|
||||||
const map = new Map<number, Recipe[]>()
|
|
||||||
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<Recipe> {
|
|
||||||
return this.api.get<Recipe>(`/recipe/${id}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
save(name: string, description: string, color: string, gloss: number, sample: number, approbationDate: string, remark: string, companyId: number): Observable<Recipe> {
|
|
||||||
const body = {name, description, color, gloss, sample, remark, companyId}
|
|
||||||
if (approbationDate) {
|
|
||||||
// @ts-ignore
|
|
||||||
body.approbationDate = approbationDate
|
|
||||||
}
|
|
||||||
return this.api.post<Recipe>('/recipe', body)
|
|
||||||
}
|
|
||||||
|
|
||||||
update(id: number, name: string, description: string, color: string, gloss: number, sample: number, approbationDate: string, remark: string, steps: Map<number, RecipeStep[]>) {
|
|
||||||
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>('/recipe', body)
|
|
||||||
}
|
|
||||||
|
|
||||||
updateExplorerModifications(id: number, notes: Map<number, string>, mixesLocationChange: Map<number, string>): Observable<void> {
|
|
||||||
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<void>('/recipe/public', body)
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: number): Observable<void> {
|
|
||||||
return this.api.delete<void>(`/recipe/${id}`)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {ApiService} from "../../shared/service/api.service";
|
import {ApiService} from '../../shared/service/api.service';
|
||||||
import {Observable} from "rxjs";
|
import {Observable} from 'rxjs';
|
||||||
import {Company} from "../../shared/model/company.model";
|
import {Company} from '../../shared/model/company.model';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {InventoryComponent} from './pages/inventory/inventory.component';
|
||||||
import {SharedModule} from "../shared/shared.module";
|
import {SharedModule} from "../shared/shared.module";
|
||||||
import {AddComponent} from './pages/add/add.component';
|
import {AddComponent} from './pages/add/add.component';
|
||||||
import {EditComponent} from './pages/edit/edit.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 {MatSortModule} from '@angular/material/sort'
|
||||||
import {FormsModule} from '@angular/forms'
|
import {FormsModule} from '@angular/forms'
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ import {FormsModule} from '@angular/forms'
|
||||||
CommonModule,
|
CommonModule,
|
||||||
MaterialRoutingModule,
|
MaterialRoutingModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
ColorsModule,
|
RecipesModule,
|
||||||
MatSortModule,
|
MatSortModule,
|
||||||
FormsModule
|
FormsModule
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<recipe-form (submitForm)="submit($event)"></recipe-form>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<div class="mt-5">
|
||||||
|
<cre-warning-alert *ngIf="!loading && !hasCompanies">
|
||||||
|
<p>Il n'y a actuellement aucune bannière enregistrée dans le système.</p>
|
||||||
|
<p *ngIf="hasCompanyEditPermission">Vous pouvez en créer une <b><a routerLink="/catalog/company/add">ici</a></b>.</p>
|
||||||
|
</cre-warning-alert>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<cre-form *ngIf="hasCompanies" #form [formControls]="controls" class="mx-auto">
|
||||||
|
<cre-form-title>Ajouter une recette</cre-form-title>
|
||||||
|
<cre-form-content>
|
||||||
|
<cre-input [control]="controls.name" label="Name" icon="form-textbox"></cre-input>
|
||||||
|
<cre-input [control]="controls.description" label="Description" icon="text"></cre-input>
|
||||||
|
<cre-input [control]="controls.color" type="color" label="Couleur" icon="palette"></cre-input>
|
||||||
|
<cre-slider-input [control]="controls.gloss" label="Lustre"></cre-slider-input>
|
||||||
|
<cre-input [control]="controls.sample" type="number" label="Échantillon" icon="pound"></cre-input>
|
||||||
|
<cre-input [control]="controls.approbationDate" type="date" label="Date d'approbation" icon="calendar"></cre-input>
|
||||||
|
<cre-input [control]="controls.remark" label="Remarque" icon="text"></cre-input>
|
||||||
|
<cre-combo-box [control]="controls.company" label="Bannière" [entries]="companyEntries$"></cre-combo-box>
|
||||||
|
</cre-form-content>
|
||||||
|
<cre-form-actions>
|
||||||
|
<cre-primary-button routerLink="/color/list">Retour</cre-primary-button>
|
||||||
|
<cre-accent-button [disabled]="form.invalid" (click)="submit()">Enregistrer</cre-accent-button>
|
||||||
|
</cre-form-actions>
|
||||||
|
</cre-form>
|
|
@ -53,7 +53,7 @@ export class ListComponent extends ErrorHandlingComponent {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
//this.fetchCompanies()
|
this.fetchCompanies()
|
||||||
this.fetchRecipes()
|
this.fetchRecipes()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {RouterModule, Routes} from '@angular/router';
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
import {ListComponent} from "./pages/list/list.component";
|
import {ListComponent} from "./pages/list/list.component";
|
||||||
import {AddComponent} from "./pages/add/add.component";
|
|
||||||
import {EditComponent} from "./pages/edit/edit.component";
|
import {EditComponent} from "./pages/edit/edit.component";
|
||||||
import {ExploreComponent} from "./pages/explore/explore.component";
|
import {ExploreComponent} from "./pages/explore/explore.component";
|
||||||
import {MixEditComponent} from "./pages/mix/mix-edit/mix-edit.component";
|
import {MixEditComponent} from "./pages/mix/mix-edit/mix-edit.component";
|
||||||
import {MixAddComponent} from "./pages/mix/mix-add/mix-add.component";
|
import {MixAddComponent} from "./pages/mix/mix-add/mix-add.component";
|
||||||
|
import {RecipeAdd} from './recipes';
|
||||||
|
|
||||||
const routes: Routes = [{
|
const routes: Routes = [{
|
||||||
path: 'list',
|
path: 'list',
|
||||||
component: ListComponent
|
component: ListComponent
|
||||||
}, {
|
}, {
|
||||||
path: 'add',
|
path: 'add',
|
||||||
component: AddComponent
|
component: RecipeAdd
|
||||||
}, {
|
}, {
|
||||||
path: 'edit/:id',
|
path: 'edit/:id',
|
||||||
component: EditComponent
|
component: EditComponent
|
||||||
|
@ -35,5 +35,5 @@ const routes: Routes = [{
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule]
|
||||||
})
|
})
|
||||||
export class ColorsRoutingModule {
|
export class RecipesRoutingModule {
|
||||||
}
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
import {NgModule} from '@angular/core'
|
import {NgModule} from '@angular/core'
|
||||||
|
|
||||||
import {ColorsRoutingModule} from './colors-routing.module'
|
import {RecipesRoutingModule} from './recipes-routing.module'
|
||||||
import {SharedModule} from '../shared/shared.module'
|
import {SharedModule} from '../shared/shared.module'
|
||||||
import {ListComponent} from './pages/list/list.component'
|
import {ListComponent} from './pages/list/list.component'
|
||||||
import {AddComponent} from './pages/add/add.component'
|
|
||||||
import {EditComponent} from './pages/edit/edit.component'
|
import {EditComponent} from './pages/edit/edit.component'
|
||||||
import {MatExpansionModule} from '@angular/material/expansion'
|
import {MatExpansionModule} from '@angular/material/expansion'
|
||||||
import {FormsModule} from '@angular/forms'
|
import {FormsModule} from '@angular/forms'
|
||||||
|
@ -19,20 +18,41 @@ import {MixEditComponent} from './pages/mix/mix-edit/mix-edit.component'
|
||||||
import {ImagesEditorComponent} from './components/images-editor/images-editor.component'
|
import {ImagesEditorComponent} from './components/images-editor/images-editor.component'
|
||||||
import {MixesCardComponent} from './components/mixes-card/mixes-card.component'
|
import {MixesCardComponent} from './components/mixes-card/mixes-card.component'
|
||||||
import {MatSortModule} from '@angular/material/sort'
|
import {MatSortModule} from '@angular/material/sort'
|
||||||
|
import {CreInputsModule} from '../shared/components/inputs/inputs.module';
|
||||||
|
import {CreButtonsModule} from '../shared/components/buttons/buttons.module';
|
||||||
|
import {RecipeAdd, RecipeForm} from './recipes';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@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: [
|
exports: [
|
||||||
UnitSelectorComponent
|
UnitSelectorComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
ColorsRoutingModule,
|
RecipesRoutingModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
MatExpansionModule,
|
MatExpansionModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
MatSortModule
|
MatSortModule,
|
||||||
|
CreInputsModule,
|
||||||
|
CreButtonsModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ColorsModule {
|
export class RecipesModule {
|
||||||
}
|
}
|
|
@ -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<ComboBoxEntry[]> = this.companyService.all.pipe(
|
||||||
|
map(companies => companies.map(c => new ComboBoxEntry(c.id, c.name))),
|
||||||
|
)
|
||||||
|
|
||||||
|
errorHandlers = [{
|
||||||
|
filter: error => error.type === `exists-recipe-company-name`,
|
||||||
|
messageProducer: error => `Une couleur avec le nom ${error.name} existe déjà pour la bannière ${error.company}`
|
||||||
|
}]
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private recipeService: RecipeService,
|
||||||
|
private companyService: CompanyService,
|
||||||
|
private appState: AppState,
|
||||||
|
errorService: ErrorService,
|
||||||
|
router: Router,
|
||||||
|
activatedRoute: ActivatedRoute
|
||||||
|
) {
|
||||||
|
super(errorService, activatedRoute, router)
|
||||||
|
this.appState.title = 'Nouvelle couleur'
|
||||||
|
}
|
||||||
|
|
||||||
|
submit(recipe: Recipe) {
|
||||||
|
this.subscribe(
|
||||||
|
this.recipeService.save(recipe),
|
||||||
|
recipe => this.urlUtils.navigateTo(`/color/edit/${recipe.id}`)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'recipe-form',
|
||||||
|
templateUrl: 'form.html'
|
||||||
|
})
|
||||||
|
export class RecipeForm extends SubscribingComponent {
|
||||||
|
@Input() recipe: Recipe | null
|
||||||
|
|
||||||
|
@Output() submitForm = new EventEmitter<Recipe>();
|
||||||
|
|
||||||
|
controls: any
|
||||||
|
companyEntries$: Observable<ComboBoxEntry[]>
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<Recipe[]> {
|
||||||
|
return this.api.get<Recipe[]>('/recipe')
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllByName(name: string): Observable<Recipe[]> {
|
||||||
|
return this.api.get<Recipe[]>(`/recipe?name=${name}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
get allByCompany(): Observable<Map<number, Recipe[]>> {
|
||||||
|
return this.all.pipe(map(recipes => {
|
||||||
|
const map = new Map<number, Recipe[]>()
|
||||||
|
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<Recipe> {
|
||||||
|
return this.api.get<Recipe>(`/recipe/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
save(recipe: Recipe): Observable<Recipe> {
|
||||||
|
const body = {
|
||||||
|
...recipe,
|
||||||
|
companyId: recipe.company
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.api.post<Recipe>('/recipe', body)
|
||||||
|
}
|
||||||
|
|
||||||
|
update(id: number, name: string, description: string, color: string, gloss: number, sample: number, approbationDate: string, remark: string, steps: Map<number, RecipeStep[]>) {
|
||||||
|
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>('/recipe', body)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateExplorerModifications(id: number, notes: Map<number, string>, mixesLocationChange: Map<number, string>): Observable<void> {
|
||||||
|
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<void>('/recipe/public', body)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(id: number): Observable<void> {
|
||||||
|
return this.api.delete<void>(`/recipe/${id}`)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
import {Component} from '@angular/core';
|
import {Component, ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-warning-alert',
|
selector: 'cre-warning-alert',
|
||||||
templateUrl: 'alerts.html'
|
templateUrl: 'alerts.html',
|
||||||
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class WarningAlert {
|
export class WarningAlert {
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
cre-form
|
cre-form
|
||||||
display: block
|
display: block
|
||||||
|
width: max-content
|
||||||
|
min-width: 50rem
|
||||||
|
margin-top: 3rem
|
||||||
|
|
||||||
mat-card
|
mat-card
|
||||||
width: inherit
|
width: inherit
|
||||||
|
min-width: inherit
|
||||||
|
|
||||||
cre-form-actions
|
cre-form-actions
|
||||||
display: flex
|
display: flex
|
||||||
|
|
|
@ -42,7 +42,7 @@ export class CreFormComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasActions(): boolean {
|
get hasActions(): boolean {
|
||||||
return this.formActions === true
|
return !!this.formActions
|
||||||
}
|
}
|
||||||
|
|
||||||
get invalid(): boolean {
|
get invalid(): boolean {
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
[ngTemplateOutletContext]="{errors: control.errors}"></ng-container>
|
[ngTemplateOutletContext]="{errors: control.errors}"></ng-container>
|
||||||
</mat-error>
|
</mat-error>
|
||||||
<mat-autocomplete #auto="matAutocomplete">
|
<mat-autocomplete #auto="matAutocomplete">
|
||||||
<mat-option *ngFor="let option of options | async" [value]="option">
|
<mat-option *ngFor="let option of entries | async" [value]="option">
|
||||||
{{option}}
|
{{option}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-autocomplete>
|
</mat-autocomplete>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
</mat-error>
|
</mat-error>
|
||||||
|
|
||||||
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
|
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
|
||||||
<mat-option *ngFor="let option of filteredOptions | async" [value]="option.key">
|
<mat-option *ngFor="let option of filteredEntries | async" [value]="option.key">
|
||||||
{{option.display ? option.display : option.value}}
|
{{option.display ? option.display : option.value}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-autocomplete>
|
</mat-autocomplete>
|
||||||
|
|
|
@ -4,19 +4,20 @@
|
||||||
matInput
|
matInput
|
||||||
type="text"
|
type="text"
|
||||||
[required]="required"
|
[required]="required"
|
||||||
[formControl]="control"
|
[formControl]="internalControl"
|
||||||
[matAutocomplete]="auto">
|
[matAutocomplete]="auto">
|
||||||
<mat-icon matSuffix [svgIcon]="icon"></mat-icon>
|
<mat-icon matSuffix [svgIcon]="icon"></mat-icon>
|
||||||
|
|
||||||
<mat-error *ngIf="control && control.invalid">
|
<mat-error *ngIf="internalControl && internalControl.invalid">
|
||||||
<span *ngIf="control.errors.required">Ce champ est requis</span>
|
<span *ngIf="internalControl.errors.invalidValue">Cette valeur est invalide</span>
|
||||||
|
<span *ngIf="internalControl.errors.required">Ce champ est requis</span>
|
||||||
<ng-container *ngIf="errors" [ngTemplateOutlet]="errors"
|
<ng-container *ngIf="errors" [ngTemplateOutlet]="errors"
|
||||||
[ngTemplateOutletContext]="{errors: control.errors}"></ng-container>
|
[ngTemplateOutletContext]="{errors: internalControl.errors}"></ng-container>
|
||||||
</mat-error>
|
</mat-error>
|
||||||
|
|
||||||
<mat-autocomplete #auto="matAutocomplete">
|
<mat-autocomplete #auto="matAutocomplete">
|
||||||
<mat-option *ngFor="let option of options | async" [value]="option.key">
|
<mat-option *ngFor="let entry of entries | async" [value]="entry.value">
|
||||||
{{option.value}}
|
{{entry.display || entry.value}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-autocomplete>
|
</mat-autocomplete>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
<input
|
<input
|
||||||
#input
|
#input
|
||||||
matInput
|
matInput
|
||||||
|
[required]="isFieldRequired"
|
||||||
[disabled]="disabled"
|
[disabled]="disabled"
|
||||||
[(ngModel)]="value"
|
[(ngModel)]="value"
|
||||||
(change)="valueChange.emit(value)"/>
|
(change)="valueChange.emit(value)"/>
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
<input
|
<input
|
||||||
#input
|
#input
|
||||||
matInput
|
matInput
|
||||||
|
[required]="isFieldRequired"
|
||||||
[formControl]="control">
|
[formControl]="control">
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
CreChipComboBoxComponent,
|
CreChipComboBoxComponent,
|
||||||
CreChipInputComponent,
|
CreChipInputComponent,
|
||||||
CreComboBoxComponent, CreFileInputComponent,
|
CreComboBoxComponent, CreFileInputComponent,
|
||||||
CreInputComponent, CrePeriodInputComponent
|
CreInputComponent, CrePeriodInputComponent, CreSliderInputComponent
|
||||||
} from './inputs'
|
} from './inputs'
|
||||||
import {MatInputModule} from '@angular/material/input'
|
import {MatInputModule} from '@angular/material/input'
|
||||||
import {MatIconModule} from '@angular/material/icon'
|
import {MatIconModule} from '@angular/material/icon'
|
||||||
|
@ -17,6 +17,7 @@ import {MatChipsModule} from '@angular/material/chips'
|
||||||
import {CreButtonsModule} from '../buttons/buttons.module'
|
import {CreButtonsModule} from '../buttons/buttons.module'
|
||||||
import {MatCheckboxModule} from '@angular/material/checkbox'
|
import {MatCheckboxModule} from '@angular/material/checkbox'
|
||||||
import {MatSelectModule} from '@angular/material/select'
|
import {MatSelectModule} from '@angular/material/select'
|
||||||
|
import {MatSliderModule} from '@angular/material/slider';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -27,7 +28,8 @@ import {MatSelectModule} from '@angular/material/select'
|
||||||
CreChipComboBoxComponent,
|
CreChipComboBoxComponent,
|
||||||
CreFileInputComponent,
|
CreFileInputComponent,
|
||||||
CreCheckboxInputComponent,
|
CreCheckboxInputComponent,
|
||||||
CrePeriodInputComponent
|
CrePeriodInputComponent,
|
||||||
|
CreSliderInputComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
|
@ -42,6 +44,7 @@ import {MatSelectModule} from '@angular/material/select'
|
||||||
CreButtonsModule,
|
CreButtonsModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
|
MatSliderModule,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
CreInputComponent,
|
CreInputComponent,
|
||||||
|
@ -51,7 +54,8 @@ import {MatSelectModule} from '@angular/material/select'
|
||||||
CreAutocompleteInputComponent,
|
CreAutocompleteInputComponent,
|
||||||
CreFileInputComponent,
|
CreFileInputComponent,
|
||||||
CreCheckboxInputComponent,
|
CreCheckboxInputComponent,
|
||||||
CrePeriodInputComponent
|
CrePeriodInputComponent,
|
||||||
|
CreSliderInputComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CreInputsModule {
|
export class CreInputsModule {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {MatAutocomplete, MatAutocompleteSelectedEvent} from '@angular/material/a
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
abstract class _CreInputBase {
|
abstract class _CreInputBase {
|
||||||
@Input() control: AbstractControl | null
|
@Input() control: FormControl | null
|
||||||
@Input() label: string
|
@Input() label: string
|
||||||
@Input() value
|
@Input() value
|
||||||
@Input() disabled = false
|
@Input() disabled = false
|
||||||
|
@ -55,9 +55,12 @@ export class CreInputComponent extends _CreInputBase implements AfterViewInit {
|
||||||
element.type = this.type
|
element.type = this.type
|
||||||
element.step = this.step.toString()
|
element.step = this.step.toString()
|
||||||
element.placeholder = this.placeholder
|
element.placeholder = this.placeholder
|
||||||
element.required = this.required
|
|
||||||
element.autocomplete = this.autocomplete ? 'on' : 'off'
|
element.autocomplete = this.autocomplete ? 'on' : 'off'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isFieldRequired(): boolean {
|
||||||
|
return this.control ? this.control.validator && this.control.validator({} as AbstractControl)?.required : this.required
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -70,7 +73,7 @@ export class CreAutocompleteInputComponent {
|
||||||
@Input() label: string
|
@Input() label: string
|
||||||
@Input() icon: string
|
@Input() icon: string
|
||||||
@Input() required = true
|
@Input() required = true
|
||||||
@Input() options: Observable<string[]>
|
@Input() entries: Observable<string[]>
|
||||||
@Input() value
|
@Input() value
|
||||||
|
|
||||||
@Output() valueChange = new EventEmitter<any>()
|
@Output() valueChange = new EventEmitter<any>()
|
||||||
|
@ -132,14 +135,70 @@ export class CreChipInputComponent implements OnInit {
|
||||||
templateUrl: 'combo-box.html',
|
templateUrl: 'combo-box.html',
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class CreComboBoxComponent {
|
export class CreComboBoxComponent implements OnInit {
|
||||||
@Input() control: AbstractControl
|
@Input() control: AbstractControl
|
||||||
@Input() label: string
|
@Input() label: string
|
||||||
@Input() icon: string
|
@Input() icon: string
|
||||||
@Input() required = true
|
@Input() required = true
|
||||||
@Input() options: Observable<ComboBoxEntry[]>
|
@Input() entries: Observable<ComboBoxEntry[]>
|
||||||
|
|
||||||
@ContentChild(TemplateRef) errors: TemplateRef<any>
|
@ContentChild(TemplateRef) errors: TemplateRef<any>
|
||||||
|
|
||||||
|
internalControl: FormControl
|
||||||
|
validValue = false
|
||||||
|
|
||||||
|
private _destroy$ = new Subject<boolean>();
|
||||||
|
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({
|
@Component({
|
||||||
|
@ -148,25 +207,27 @@ export class CreComboBoxComponent {
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class CreChipComboBoxComponent extends CreChipInputComponent implements OnDestroy {
|
export class CreChipComboBoxComponent extends CreChipInputComponent implements OnDestroy {
|
||||||
@Input() options: Observable<ComboBoxEntry[]>
|
@Input() entries: Observable<ComboBoxEntry[]>
|
||||||
|
|
||||||
@ContentChild(TemplateRef) errors: TemplateRef<any>
|
@ContentChild(TemplateRef) errors: TemplateRef<any>
|
||||||
@ViewChild('chipInput') chipInput: ElementRef<HTMLInputElement>
|
@ViewChild('chipInput') chipInput: ElementRef<HTMLInputElement>
|
||||||
@ViewChild('auto') matAutocomplete: MatAutocomplete
|
@ViewChild('auto') matAutocomplete: MatAutocomplete
|
||||||
|
|
||||||
filteredOptions: Observable<ComboBoxEntry[]>
|
filteredEntries: Observable<ComboBoxEntry[]>
|
||||||
|
|
||||||
private _options: ComboBoxEntry[]
|
private _entries: ComboBoxEntry[]
|
||||||
private _destroy$ = new Subject()
|
private _destroy$ = new Subject()
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
|
|
||||||
this.options.pipe(takeUntil(this._destroy$))
|
this.entries.pipe(takeUntil(this._destroy$))
|
||||||
.subscribe({next: options => this._options = options})
|
.subscribe({
|
||||||
|
next: entries => this._entries = entries
|
||||||
|
})
|
||||||
|
|
||||||
this.filteredOptions = this.inputControl.valueChanges.pipe(
|
this.filteredEntries = this.inputControl.valueChanges.pipe(
|
||||||
map((query: string | null) => query ? this._filter(query) : this._options.slice())
|
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[] {
|
private _filter(query: string): ComboBoxEntry[] {
|
||||||
const filterValue = query.toString().toLowerCase()
|
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 {
|
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 {
|
export class ComboBoxEntry {
|
||||||
constructor(
|
constructor(
|
||||||
public key: any,
|
public key: any,
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<div>
|
||||||
|
<p class="slider-label">{{label}}</p>
|
||||||
|
<mat-slider
|
||||||
|
*ngIf="control"
|
||||||
|
[min]="min"
|
||||||
|
[max]="max"
|
||||||
|
[value]="control.value"
|
||||||
|
[disabled]="control.disabled"
|
||||||
|
[thumbLabel]="thumbLabel"
|
||||||
|
[displayWith]="formatValueForDisplay"
|
||||||
|
(valueChange)="control.setValue($event)">
|
||||||
|
</mat-slider>
|
||||||
|
</div>
|
|
@ -1,25 +1,21 @@
|
||||||
import {Material} from './material.model'
|
import {Material} from './material.model'
|
||||||
import {LocalDate} from 'js-joda'
|
|
||||||
import {Company} from './company.model'
|
import {Company} from './company.model'
|
||||||
import {Group} from './user'
|
import {Group} from './user'
|
||||||
|
|
||||||
export class Recipe {
|
export class Recipe {
|
||||||
constructor(
|
public id: number
|
||||||
public id: number,
|
public name: string
|
||||||
public name: string,
|
public description: string
|
||||||
public description: string,
|
public color: string
|
||||||
public color: string,
|
public gloss: number
|
||||||
public gloss: number,
|
public sample: number
|
||||||
public sample: number,
|
public approbationDate: string
|
||||||
public approbationDate: string,
|
public remark: string
|
||||||
public approbationExpired: boolean,
|
public company: Company
|
||||||
public remark: string,
|
public mixes: Mix[]
|
||||||
public company: Company,
|
public approbationExpired: boolean
|
||||||
public mixes: Mix[],
|
public groupsInformation: RecipeGroupInformation[]
|
||||||
public groupsInformation: RecipeGroupInformation[],
|
public imagesUrls: string[]
|
||||||
public imagesUrls: string[]
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RecipeGroupInformation {
|
export class RecipeGroupInformation {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {Component, Input} from '@angular/core'
|
import {Component, Input} from '@angular/core'
|
||||||
import {SubscribingComponent} from '../../shared/components/subscribing.component'
|
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 {ErrorService} from '../../shared/service/error.service'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {Recipe} from '../../shared/model/recipe.model'
|
import {Recipe} from '../../shared/model/recipe.model'
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<cre-input [control]="controls.buggy" label="Chariot" icon="pound"></cre-input>
|
<cre-input [control]="controls.buggy" label="Chariot" icon="pound"></cre-input>
|
||||||
<cre-autocomplete-input
|
<cre-autocomplete-input
|
||||||
[control]="controls.company"
|
[control]="controls.company"
|
||||||
[options]="companies$"
|
[entries]="companies$"
|
||||||
label="Bannière"
|
label="Bannière"
|
||||||
icon="domain">
|
icon="domain">
|
||||||
</cre-autocomplete-input>
|
</cre-autocomplete-input>
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
<cre-chip-combo-box
|
<cre-chip-combo-box
|
||||||
#finishInput
|
#finishInput
|
||||||
[control]="controls.finish"
|
[control]="controls.finish"
|
||||||
[options]="finish$"
|
[entries]="finish$"
|
||||||
label="Fini"
|
label="Fini"
|
||||||
icon="flare">
|
icon="flare">
|
||||||
</cre-chip-combo-box>
|
</cre-chip-combo-box>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {chipListRequired, ComboBoxEntry, CreChipComboBoxComponent} from '../../s
|
||||||
import {CreFormComponent} from '../../shared/components/forms/forms'
|
import {CreFormComponent} from '../../shared/components/forms/forms'
|
||||||
import {TouchUpKitProductEditor} from './product-editor'
|
import {TouchUpKitProductEditor} from './product-editor'
|
||||||
import {FormControl, Validators} from '@angular/forms'
|
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 {CompanyService} from '../../company/service/company.service'
|
||||||
import {ErrorService} from '../../shared/service/error.service'
|
import {ErrorService} from '../../shared/service/error.service'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {AccountService} from '../../accounts/services/account.service'
|
||||||
import {ErrorService} from '../../shared/service/error.service'
|
import {ErrorService} from '../../shared/service/error.service'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {Permission} from '../../shared/model/user'
|
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 {AppState} from '../../shared/app-state'
|
||||||
import {map} from 'rxjs/operators'
|
import {map} from 'rxjs/operators'
|
||||||
import {LocalDate, Period} from 'js-joda'
|
import {LocalDate, Period} from 'js-joda'
|
||||||
|
|
Loading…
Reference in New Issue