diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index be757b7..7057e34 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -3,7 +3,6 @@ import {Routes, RouterModule} from '@angular/router' import {CatalogComponent} from './pages/catalog/catalog.component' import {AdministrationComponent} from './pages/administration/administration.component' import {MiscComponent} from './pages/others/misc.component' -import {TouchupkitComponent} from './pages/others/touchupkit/touchupkit.component' const routes: Routes = [{ @@ -49,12 +48,12 @@ const routes: Routes = [{ path: 'misc', component: MiscComponent, children: [{ - path: 'touchupkit', - component: TouchupkitComponent + path: 'touch-up-kit', + loadChildren: () => import('./modules/touch-up-kit/touch-up-kit.module').then(m => m.TouchUpKitModule) }, { path: '', pathMatch: 'full', - redirectTo: 'touchupkit' + redirectTo: 'touch-up-kit' }] }] diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 9de024d..c90abde 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,30 +1,34 @@ -import {DomSanitizer} from '@angular/platform-browser'; -import {NgModule} from '@angular/core'; +import {DomSanitizer} from '@angular/platform-browser' +import {NgModule} from '@angular/core' -import {AppRoutingModule} from './app-routing.module'; -import {AppComponent} from './app.component'; -import {MatIconRegistry} from "@angular/material/icon"; -import {SharedModule} from "./modules/shared/shared.module"; -import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; -import {CatalogComponent} from './pages/catalog/catalog.component'; -import {CompanyModule} from './modules/company/company.module'; -import { AdministrationComponent } from './pages/administration/administration.component'; -import { MiscComponent } from './pages/others/misc.component'; -import { TouchupkitComponent } from './pages/others/touchupkit/touchupkit.component'; +import {AppRoutingModule} from './app-routing.module' +import {AppComponent} from './app.component' +import {MatIconRegistry} from '@angular/material/icon' +import {SharedModule} from './modules/shared/shared.module' +import {BrowserAnimationsModule} from '@angular/platform-browser/animations' +import {CatalogComponent} from './pages/catalog/catalog.component' +import {CompanyModule} from './modules/company/company.module' +import {AdministrationComponent} from './pages/administration/administration.component' +import {MiscComponent} from './pages/others/misc.component' +import {CreTablesModule} from './modules/shared/components/tables/tables.module' +import {CreButtonsModule} from './modules/shared/components/buttons/buttons.module' +import {TouchUpKitModule} from './modules/touch-up-kit/touch-up-kit.module' @NgModule({ declarations: [ AppComponent, CatalogComponent, AdministrationComponent, - MiscComponent, - TouchupkitComponent + MiscComponent ], imports: [ AppRoutingModule, SharedModule, BrowserAnimationsModule, - CompanyModule + CompanyModule, + CreTablesModule, + CreButtonsModule, + TouchUpKitModule ], providers: [], bootstrap: [AppComponent] diff --git a/src/app/modules/colors/components/recipe-info/recipe-info.component.html b/src/app/modules/colors/components/recipe-info/recipe-info.component.html index 5e4831a..ba42447 100644 --- a/src/app/modules/colors/components/recipe-info/recipe-info.component.html +++ b/src/app/modules/colors/components/recipe-info/recipe-info.component.html @@ -1,17 +1,12 @@

{{recipe.company.name}} - {{recipe.name}}

-
-
{{recipe.gloss}}%
-
+

Échantillon #{{recipe.sample}}

-

Approuvée le {{recipe.approbationDate}}

+

Approuvée le {{approbationDate}}

Non approuvée

diff --git a/src/app/modules/colors/components/recipe-info/recipe-info.component.ts b/src/app/modules/colors/components/recipe-info/recipe-info.component.ts index 35145bc..6a619d7 100644 --- a/src/app/modules/colors/components/recipe-info/recipe-info.component.ts +++ b/src/app/modules/colors/components/recipe-info/recipe-info.component.ts @@ -1,5 +1,6 @@ import {AfterViewInit, Component, Input} from '@angular/core' import {getRecipeLuma, recipeApprobationExpired, Recipe} from '../../../shared/model/recipe.model' +import {formatDate} from '../../../shared/utils/utils' @Component({ selector: 'cre-recipe-info', @@ -13,15 +14,14 @@ export class RecipeInfoComponent implements AfterViewInit { isBPacExtensionInstalled = false ngAfterViewInit(): void { - this.isBPacExtensionInstalled = document.querySelectorAll('.bpac-extension-installed').length > 0 } + get approbationDate(): string { + return formatDate(this.recipe.approbationDate) + } + get isApprobationExpired(): boolean { return recipeApprobationExpired(this.recipe) } - - get isDarkColor(): boolean { - return getRecipeLuma(this.recipe) < 100 - } } diff --git a/src/app/modules/colors/pages/explore/explore.component.ts b/src/app/modules/colors/pages/explore/explore.component.ts index 89665ec..1299087 100644 --- a/src/app/modules/colors/pages/explore/explore.component.ts +++ b/src/app/modules/colors/pages/explore/explore.component.ts @@ -13,6 +13,7 @@ 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 {Title} from '@angular/platform-browser' @Component({ selector: 'cre-explore', @@ -49,6 +50,7 @@ export class ExploreComponent extends ErrorHandlingComponent { private alertService: AlertService, private accountService: AccountService, private appState: AppState, + private titleService: Title, errorService: ErrorService, router: Router, activatedRoute: ActivatedRoute @@ -68,6 +70,7 @@ export class ExploreComponent extends ErrorHandlingComponent { id, r => { this.recipe = r + this.titleService.setTitle(r.name) if (recipeMixCount(this.recipe) <= 0 || recipeStepCount(this.recipe) <= 0) { this.alertService.pushWarning('Cette recette n\'est pas complète') diff --git a/src/app/modules/colors/services/recipe.service.ts b/src/app/modules/colors/services/recipe.service.ts index 5e80f25..1cda0ce 100644 --- a/src/app/modules/colors/services/recipe.service.ts +++ b/src/app/modules/colors/services/recipe.service.ts @@ -17,6 +17,10 @@ export class RecipeService { return this.api.get('/recipe') } + 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 = [] diff --git a/src/app/modules/shared/components/action-bar/action-bar.html b/src/app/modules/shared/components/action-bar/action-bar.html new file mode 100644 index 0000000..4bad334 --- /dev/null +++ b/src/app/modules/shared/components/action-bar/action-bar.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/src/app/modules/shared/components/action-bar/action-bar.module.ts b/src/app/modules/shared/components/action-bar/action-bar.module.ts new file mode 100644 index 0000000..5188c1b --- /dev/null +++ b/src/app/modules/shared/components/action-bar/action-bar.module.ts @@ -0,0 +1,15 @@ +import {NgModule} from '@angular/core' +import {CreActionBar, CreActionGroup} from './action-bar' + +@NgModule({ + exports: [ + CreActionBar, + CreActionGroup + ], + declarations: [ + CreActionBar, + CreActionGroup + ] +}) +export class CreActionBarModule { +} diff --git a/src/app/modules/shared/components/action-bar/action-bar.ts b/src/app/modules/shared/components/action-bar/action-bar.ts new file mode 100644 index 0000000..506bed9 --- /dev/null +++ b/src/app/modules/shared/components/action-bar/action-bar.ts @@ -0,0 +1,14 @@ +import {Component} from '@angular/core' + +@Component({ + selector: 'cre-action-group', + templateUrl: 'action-group.html', + styleUrls: ['action-group.sass'] +}) +export class CreActionGroup {} + +@Component({ + selector: 'cre-action-bar', + templateUrl: 'action-bar.html' +}) +export class CreActionBar {} diff --git a/src/app/modules/shared/components/action-bar/action-group.html b/src/app/modules/shared/components/action-bar/action-group.html new file mode 100644 index 0000000..dfdbcc7 --- /dev/null +++ b/src/app/modules/shared/components/action-bar/action-group.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/src/app/modules/shared/components/action-bar/action-group.sass b/src/app/modules/shared/components/action-bar/action-group.sass new file mode 100644 index 0000000..4c50bf7 --- /dev/null +++ b/src/app/modules/shared/components/action-bar/action-group.sass @@ -0,0 +1,4 @@ +div + display: flex + flex-direction: row + gap: 1rem diff --git a/src/app/modules/shared/components/buttons/buttons.module.ts b/src/app/modules/shared/components/buttons/buttons.module.ts new file mode 100644 index 0000000..1dd694f --- /dev/null +++ b/src/app/modules/shared/components/buttons/buttons.module.ts @@ -0,0 +1,22 @@ +import {NgModule} from '@angular/core' +import {CreAccentButtonComponent, CreButtonComponent, CrePrimaryButtonComponent, CreWarnButtonComponent} from './buttons' +import {MatButtonModule} from '@angular/material/button' + +@NgModule({ + declarations: [ + CreButtonComponent, + CrePrimaryButtonComponent, + CreAccentButtonComponent, + CreWarnButtonComponent + ], + imports: [ + MatButtonModule + ], + exports: [ + CrePrimaryButtonComponent, + CreAccentButtonComponent, + CreWarnButtonComponent + ] +}) +export class CreButtonsModule { +} diff --git a/src/app/modules/shared/components/buttons/buttons.ts b/src/app/modules/shared/components/buttons/buttons.ts new file mode 100644 index 0000000..7b3679e --- /dev/null +++ b/src/app/modules/shared/components/buttons/buttons.ts @@ -0,0 +1,51 @@ +import {Component, Input} from '@angular/core' +import {ThemePalette} from '@angular/material/core' + +@Component({ + selector: 'cre-button', + template: ` + + ` +}) +export class CreButtonComponent { + @Input() color: ThemePalette + @Input() disabled = false +} + +@Component({ + selector: 'cre-primary-button', + template: ` + + + + ` +}) +export class CrePrimaryButtonComponent { + @Input() disabled = false +} + +@Component({ + selector: 'cre-accent-button', + template: ` + + + + ` +}) +export class CreAccentButtonComponent { + @Input() disabled = false +} + +@Component({ + selector: 'cre-warn-button', + template: ` + + + + ` +}) +export class CreWarnButtonComponent { + @Input() disabled = false +} diff --git a/src/app/modules/shared/components/color-preview/color-preview.html b/src/app/modules/shared/components/color-preview/color-preview.html new file mode 100644 index 0000000..76b6bf6 --- /dev/null +++ b/src/app/modules/shared/components/color-preview/color-preview.html @@ -0,0 +1,6 @@ +
+
{{recipe.gloss}}%
+
diff --git a/src/app/modules/shared/components/color-preview/color-preview.sass b/src/app/modules/shared/components/color-preview/color-preview.sass new file mode 100644 index 0000000..28343ed --- /dev/null +++ b/src/app/modules/shared/components/color-preview/color-preview.sass @@ -0,0 +1,20 @@ +.recipe-color-circle + color: black + width: 2.2rem + height: 2.2rem + border-radius: 1.1rem + margin-left: 1rem + font-size: 13px + + &.dark-mode + color: white + width: 2.3rem + height: 2.3rem + border: solid 1px white + + div + position: absolute + width: 2rem + text-align: center + margin-top: 7px + margin-left: 1px diff --git a/src/app/modules/shared/components/color-preview/color-preview.ts b/src/app/modules/shared/components/color-preview/color-preview.ts new file mode 100644 index 0000000..d713ec2 --- /dev/null +++ b/src/app/modules/shared/components/color-preview/color-preview.ts @@ -0,0 +1,15 @@ +import {getRecipeLuma, Recipe} from '../../model/recipe.model' +import {Component, Input} from '@angular/core' + +@Component({ + selector: 'cre-color-preview', + templateUrl: 'color-preview.html', + styleUrls: ['color-preview.sass'] +}) +export class CreColorPreview { + @Input() recipe: Recipe + + get isDarkColor(): boolean { + return getRecipeLuma(this.recipe) < 100 + } +} diff --git a/src/app/modules/shared/components/forms/form.html b/src/app/modules/shared/components/forms/form.html new file mode 100644 index 0000000..1d6e89b --- /dev/null +++ b/src/app/modules/shared/components/forms/form.html @@ -0,0 +1,15 @@ + + + + + + + +
+ +
+
+ + + +
diff --git a/src/app/modules/shared/components/forms/forms.module.ts b/src/app/modules/shared/components/forms/forms.module.ts new file mode 100644 index 0000000..2ee4a91 --- /dev/null +++ b/src/app/modules/shared/components/forms/forms.module.ts @@ -0,0 +1,28 @@ +import {NgModule} from '@angular/core' +import {CreFormActions, CreFormComponent, 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' + +@NgModule({ + declarations: [ + CreFormComponent, + CreFormTitle, + CreFormContent, + CreFormActions + ], + exports: [ + CreFormComponent, + CreFormTitle, + CreFormContent, + CreFormActions + ], + imports: [ + MatCardModule, + CommonModule, + MatButtonModule, + ReactiveFormsModule + ] +}) +export class CreFormsModule {} diff --git a/src/app/modules/shared/components/forms/forms.sass b/src/app/modules/shared/components/forms/forms.sass new file mode 100644 index 0000000..fffedc8 --- /dev/null +++ b/src/app/modules/shared/components/forms/forms.sass @@ -0,0 +1,10 @@ +cre-form + display: block + + mat-card + width: inherit + + cre-form-actions + display: flex + flex-direction: row + gap: 1rem diff --git a/src/app/modules/shared/components/forms/forms.ts b/src/app/modules/shared/components/forms/forms.ts new file mode 100644 index 0000000..5770d23 --- /dev/null +++ b/src/app/modules/shared/components/forms/forms.ts @@ -0,0 +1,51 @@ +import {Component, ContentChild, Directive, Input, OnInit, ViewEncapsulation} from '@angular/core' +import {FormBuilder, FormGroup} from '@angular/forms' + +@Directive({ + selector: 'cre-form-title' +}) +export class CreFormTitle { +} + +@Directive({ + selector: 'cre-form-content' +}) +export class CreFormContent { +} + +@Directive({ + selector: 'cre-form-actions' +}) +export class CreFormActions { + +} + +@Component({ + selector: 'cre-form', + templateUrl: './form.html', + styleUrls: ['forms.sass'], + encapsulation: ViewEncapsulation.None +}) +export class CreFormComponent implements OnInit { + @ContentChild(CreFormActions) formActions: CreFormActions + @Input() formControls: { [key: string]: any } + + form: FormGroup + + constructor( + private formBuilder: FormBuilder + ) { + } + + ngOnInit(): void { + this.form = this.formBuilder.group(this.formControls) + } + + get hasActions(): boolean { + return this.formActions === true + } + + get invalid(): boolean { + return !this.form || this.form.invalid + } +} diff --git a/src/app/modules/shared/components/info-banner/info-banner.component.sass b/src/app/modules/shared/components/info-banner/info-banner.component.sass new file mode 100644 index 0000000..558af2c --- /dev/null +++ b/src/app/modules/shared/components/info-banner/info-banner.component.sass @@ -0,0 +1,16 @@ +@import "~src/custom-theme" + +.info-banner-wrapper + background-color: $color-primary + color: $light-primary-text + padding: 1rem + +.info-banner-section-wrapper + margin-right: 3rem + +h3 + text-decoration: underline + font-weight: bold + +p + margin-bottom: 0 diff --git a/src/app/modules/shared/components/info-banner/info-banner.component.ts b/src/app/modules/shared/components/info-banner/info-banner.component.ts new file mode 100644 index 0000000..7a0b379 --- /dev/null +++ b/src/app/modules/shared/components/info-banner/info-banner.component.ts @@ -0,0 +1,49 @@ +import {Component} from '@angular/core' + +@Component({ + selector: 'info-banner', + template: ` +
+ +
+ `, + styleUrls: ['info-banner.component.sass'] +}) +export class InfoBannerComponent { +} + +@Component({ + selector: 'info-banner-title', + template: ` +

+ +

+ `, + styleUrls: ['info-banner.component.sass'] +}) +export class InfoBannerTitleComponent { +} + +@Component({ + selector: 'info-banner-content', + template: ` +
+ +
+ `, + styleUrls: ['info-banner.component.sass'] +}) +export class InfoBannerContentComponent { +} + +@Component({ + selector: 'info-banner-section', + template: ` +
+ +
+ `, + styleUrls: ['info-banner.component.sass'] +}) +export class InfoBannerSectionComponent { +} diff --git a/src/app/modules/shared/components/info-banner/info-banner.module.ts b/src/app/modules/shared/components/info-banner/info-banner.module.ts new file mode 100644 index 0000000..4afef82 --- /dev/null +++ b/src/app/modules/shared/components/info-banner/info-banner.module.ts @@ -0,0 +1,24 @@ +import {NgModule} from '@angular/core' +import { + InfoBannerComponent, + InfoBannerContentComponent, + InfoBannerSectionComponent, + InfoBannerTitleComponent +} from './info-banner.component' + +@NgModule({ + declarations: [ + InfoBannerComponent, + InfoBannerTitleComponent, + InfoBannerContentComponent, + InfoBannerSectionComponent + ], + exports: [ + InfoBannerComponent, + InfoBannerTitleComponent, + InfoBannerContentComponent, + InfoBannerSectionComponent + ] +}) +export class InfoBannerModule { +} diff --git a/src/app/modules/shared/components/inputs/autocomplete-input.html b/src/app/modules/shared/components/inputs/autocomplete-input.html new file mode 100644 index 0000000..bc21b24 --- /dev/null +++ b/src/app/modules/shared/components/inputs/autocomplete-input.html @@ -0,0 +1,31 @@ + + {{label}} + + + + + Ce champ est requis + + + + + {{option}} + + + diff --git a/src/app/modules/shared/components/inputs/chip-combo-box.html b/src/app/modules/shared/components/inputs/chip-combo-box.html new file mode 100644 index 0000000..443ff0c --- /dev/null +++ b/src/app/modules/shared/components/inputs/chip-combo-box.html @@ -0,0 +1,37 @@ + + {{label}} + + + {{value}} + cancel + + + + + + + + Ce champ est requis + + + + + + {{option.display ? option.display : option.value}} + + + diff --git a/src/app/modules/shared/components/inputs/chip-input.html b/src/app/modules/shared/components/inputs/chip-input.html new file mode 100644 index 0000000..4faf8f5 --- /dev/null +++ b/src/app/modules/shared/components/inputs/chip-input.html @@ -0,0 +1,23 @@ + + {{label}} + + + {{value}} + cancel + + + + + diff --git a/src/app/modules/shared/components/inputs/combo-box.html b/src/app/modules/shared/components/inputs/combo-box.html new file mode 100644 index 0000000..5170f8c --- /dev/null +++ b/src/app/modules/shared/components/inputs/combo-box.html @@ -0,0 +1,22 @@ + + {{label}} + + + + + Ce champ est requis + + + + + + {{option.value}} + + + diff --git a/src/app/modules/shared/components/inputs/input.html b/src/app/modules/shared/components/inputs/input.html new file mode 100644 index 0000000..d7ef1cd --- /dev/null +++ b/src/app/modules/shared/components/inputs/input.html @@ -0,0 +1,28 @@ + + {{label}} + + + + + Ce champ est requis + + + diff --git a/src/app/modules/shared/components/inputs/inputs.module.ts b/src/app/modules/shared/components/inputs/inputs.module.ts new file mode 100644 index 0000000..d28ce15 --- /dev/null +++ b/src/app/modules/shared/components/inputs/inputs.module.ts @@ -0,0 +1,46 @@ +import {NgModule} from '@angular/core' +import { + CreAutocompleteInputComponent, + CreChipComboBoxComponent, + CreChipInputComponent, + CreComboBoxComponent, + CreInputComponent +} from './inputs' +import {MatInputModule} from '@angular/material/input' +import {MatIconModule} from '@angular/material/icon' +import {FormsModule, ReactiveFormsModule} from '@angular/forms' +import {CommonModule} from '@angular/common' +import {MatCardModule} from '@angular/material/card' +import {MatListModule} from '@angular/material/list' +import {MatAutocompleteModule} from '@angular/material/autocomplete' +import {MatChipsModule} from '@angular/material/chips' + +@NgModule({ + declarations: [ + CreInputComponent, + CreChipInputComponent, + CreAutocompleteInputComponent, + CreComboBoxComponent, + CreChipComboBoxComponent + ], + imports: [ + MatInputModule, + MatAutocompleteModule, + MatIconModule, + ReactiveFormsModule, + CommonModule, + MatCardModule, + MatListModule, + MatChipsModule, + FormsModule, + ], + exports: [ + CreInputComponent, + CreComboBoxComponent, + CreChipComboBoxComponent, + CreChipInputComponent, + CreAutocompleteInputComponent + ] +}) +export class CreInputsModule { +} diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts new file mode 100644 index 0000000..1a64d73 --- /dev/null +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -0,0 +1,190 @@ +import { + Component, + ContentChild, + ElementRef, + EventEmitter, + Input, + OnDestroy, + OnInit, + Output, + TemplateRef, + ViewChild, + ViewEncapsulation +} from '@angular/core' +import {AbstractControl, FormControl, ValidationErrors, ValidatorFn} from '@angular/forms' +import {COMMA, ENTER} from '@angular/cdk/keycodes' +import {Observable, Subject} from 'rxjs' +import {map, takeUntil} from 'rxjs/operators' +import {MatChipInputEvent} from '@angular/material/chips' +import {MatAutocomplete, MatAutocompleteSelectedEvent} from '@angular/material/autocomplete' + +@Component({ + selector: 'cre-input', + templateUrl: 'input.html', + encapsulation: ViewEncapsulation.None +}) +export class CreInputComponent { + @Input() control: FormControl | null + @Input() type = 'text' + @Input() label: string + @Input() icon: string + @Input() required = true + @Input() autocomplete = true + @Input() placeholder: string | null + @Input() step = 1 + @Input() value + + @Output() valueChange = new EventEmitter() + + @ContentChild(TemplateRef) errors: TemplateRef +} + +@Component({ + selector: 'cre-autocomplete-input', + templateUrl: 'autocomplete-input.html', + encapsulation: ViewEncapsulation.None +}) +export class CreAutocompleteInputComponent { + @Input() control: FormControl | null + @Input() label: string + @Input() icon: string + @Input() required = true + @Input() options: Observable + @Input() value + + @Output() valueChange = new EventEmitter() + + @ContentChild(TemplateRef) errors: TemplateRef +} + +@Component({ + selector: 'cre-chip-input', + templateUrl: 'chip-input.html', + encapsulation: ViewEncapsulation.None +}) +export class CreChipInputComponent implements OnInit { + @Input() control: FormControl + @Input() label: string + @Input() icon: string + @Input() required = true + + inputControl = new FormControl() + + readonly separatorKeysCodes = [ENTER, COMMA] + + selectedValues = [] + + ngOnInit(): void { + if (this.control.value) { + this.selectedValues = this.control.value + } + } + + add(event: MatChipInputEvent): void { + const input = event.input + const value = event.value + + if ((value || '').trim()) { + this.selectedValues.push(value.trim()) + } + + if (input) { + input.value = '' + } + + this.inputControl.setValue(null) + this.control.setValue(this.selectedValues) + } + + remove(value): void { + const index = this.selectedValues.indexOf(value) + + if (index >= 0) { + this.selectedValues.splice(index, 1) + this.control.setValue(this.selectedValues) + } + } +} + +@Component({ + selector: 'cre-combo-box', + templateUrl: 'combo-box.html', + encapsulation: ViewEncapsulation.None +}) +export class CreComboBoxComponent { + @Input() control: FormControl + @Input() label: string + @Input() icon: string + @Input() required = true + @Input() options: Observable + + @ContentChild(TemplateRef) errors: TemplateRef +} + +@Component({ + selector: 'cre-chip-combo-box', + templateUrl: 'chip-combo-box.html', + encapsulation: ViewEncapsulation.None +}) +export class CreChipComboBoxComponent extends CreChipInputComponent implements OnDestroy { + @Input() options: Observable + + @ContentChild(TemplateRef) errors: TemplateRef + @ViewChild('chipInput') chipInput: ElementRef + @ViewChild('auto') matAutocomplete: MatAutocomplete + + filteredOptions: Observable + + private _options: ComboBoxEntry[] + private _destroy$ = new Subject() + + ngOnInit() { + super.ngOnInit() + + this.options.pipe(takeUntil(this._destroy$)) + .subscribe({next: options => this._options = options}) + + this.filteredOptions = this.inputControl.valueChanges.pipe( + map((query: string | null) => query ? this._filter(query) : this._options.slice()) + ) + } + + ngOnDestroy(): void { + this._destroy$.complete() + } + + selected(event: MatAutocompleteSelectedEvent) { + this.selectedValues.push(this.findValueByKey(event.option.value)) + this.chipInput.nativeElement.value = '' + this.inputControl.setValue(null) + this.control.setValue(this.selectedValues) + } + + get empty(): boolean { + return this.selectedValues.length <= 0 + } + + private _filter(query: string): ComboBoxEntry[] { + const filterValue = query.toString().toLowerCase() + return this._options.filter(option => option.value.toString().toLowerCase().indexOf(filterValue) === 0) + } + + private findValueByKey(key: any): any { + return this._options.filter(o => o.key === key)[0].value + } +} + +export class ComboBoxEntry { + constructor( + public key: any, + public value: any, + public display?: any + ) { + } +} + +export function chipListRequired(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + return !control.value || control.value.length <= 0 ? {required: true} : null + } +} diff --git a/src/app/modules/shared/components/nav/nav.component.sass b/src/app/modules/shared/components/nav/nav.component.sass index 05f5622..26455a3 100644 --- a/src/app/modules/shared/components/nav/nav.component.sass +++ b/src/app/modules/shared/components/nav/nav.component.sass @@ -3,7 +3,6 @@ nav position: relative z-index: 90 - padding-bottom: 1px a opacity: 1 diff --git a/src/app/modules/shared/components/tables/table.html b/src/app/modules/shared/components/tables/table.html new file mode 100644 index 0000000..46560ec --- /dev/null +++ b/src/app/modules/shared/components/tables/table.html @@ -0,0 +1,12 @@ + + + + + + +
diff --git a/src/app/modules/shared/components/tables/table.sass b/src/app/modules/shared/components/tables/table.sass new file mode 100644 index 0000000..4458b6e --- /dev/null +++ b/src/app/modules/shared/components/tables/table.sass @@ -0,0 +1,12 @@ +@import "~src/custom-theme" + +cre-table + display: block + width: max-content + + tr + &:hover + background-color: darken(white, 5%) + + &.cre-row-selected + background-color: darken(white, 10%) diff --git a/src/app/modules/shared/components/tables/tables.module.ts b/src/app/modules/shared/components/tables/tables.module.ts new file mode 100644 index 0000000..2e9576d --- /dev/null +++ b/src/app/modules/shared/components/tables/tables.module.ts @@ -0,0 +1,21 @@ +import {NgModule} from '@angular/core' +import {MatTableModule} from '@angular/material/table' +import {CommonModule} from '@angular/common' +import {CreInteractiveCell, CreTable} from './tables' + +@NgModule({ + declarations: [ + CreTable, + CreInteractiveCell + ], + imports: [ + MatTableModule, + CommonModule + ], + exports: [ + CreTable, + CreInteractiveCell, + ] +}) +export class CreTablesModule { +} diff --git a/src/app/modules/shared/components/tables/tables.ts b/src/app/modules/shared/components/tables/tables.ts new file mode 100644 index 0000000..59cec5c --- /dev/null +++ b/src/app/modules/shared/components/tables/tables.ts @@ -0,0 +1,83 @@ +import { + AfterContentInit, + Component, + ContentChildren, + Directive, + HostBinding, + Input, + QueryList, + ViewChild, + ViewEncapsulation +} from '@angular/core' +import {MatColumnDef, MatHeaderRowDef, MatRowDef, MatTable} from '@angular/material/table' + +@Directive({ + selector: '[creInteractiveCell]' +}) +export class CreInteractiveCell implements AfterContentInit { + @Input('creInteractiveCell') index: number + + @HostBinding() hidden = true + + private _selectedIndex = 0 + private _hoverIndex = 0 + + ngAfterContentInit(): void { + this.hidden = this.isHidden + } + + set hoverIndex(index: number) { + this._hoverIndex = index + this.hidden = this.isHidden + } + + set selectedIndex(index: number) { + this._selectedIndex = index + this.hidden = this.isHidden + } + + get isHidden(): boolean { + return this._hoverIndex !== this.index && this._selectedIndex !== this.index + } +} + +@Component({ + selector: 'cre-table', + templateUrl: 'table.html', + styleUrls: ['table.sass'], + encapsulation: ViewEncapsulation.None +}) +export class CreTable implements AfterContentInit { + @ContentChildren(MatHeaderRowDef) headerRowDefs: QueryList + @ContentChildren(MatRowDef) rowDefs: QueryList> + @ContentChildren(MatColumnDef) columnDefs: QueryList + + @ContentChildren(CreInteractiveCell, {descendants: true}) interactiveCells: QueryList + + @ViewChild(MatTable, {static: true}) table: MatTable + + @Input() columns: string[] + @Input() dataSource: T[] + @Input() interactive = true + + selectedIndex = 0 + + 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)) + } + + onRowHover(index: number) { + if (this.interactive) { + this.interactiveCells.forEach(cell => cell.hoverIndex = index) + } + } + + onRowSelected(index: number) { + if (this.interactive) { + this.selectedIndex = index + this.interactiveCells.forEach(cell => cell.selectedIndex = index) + } + } +} diff --git a/src/app/modules/shared/directives/var.directive.ts b/src/app/modules/shared/directives/var.directive.ts new file mode 100644 index 0000000..9aad369 --- /dev/null +++ b/src/app/modules/shared/directives/var.directive.ts @@ -0,0 +1,25 @@ +import {Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core' + +@Directive({ + selector: '[ngVar]' +}) +export class VarDirective { + context: any = {} + + constructor( + private vcRef: ViewContainerRef, + private templateRef: TemplateRef + ) { + } + + @Input() + set ngVar(context: any) { + this.context.$implicit = this.context.ngVar = context + this.updateView() + } + + private updateView() { + this.vcRef.clear() + this.vcRef.createEmbeddedView(this.templateRef, this.context) + } +} diff --git a/src/app/modules/shared/model/recipe.model.ts b/src/app/modules/shared/model/recipe.model.ts index f48ec29..b1137c4 100644 --- a/src/app/modules/shared/model/recipe.model.ts +++ b/src/app/modules/shared/model/recipe.model.ts @@ -11,7 +11,7 @@ export class Recipe { public color: string, public gloss: number, public sample: number, - public approbationDate: LocalDate, + public approbationDate: string, public remark: string, public company: Company, public mixes: Mix[], diff --git a/src/app/modules/shared/model/touch-up-kit.model.ts b/src/app/modules/shared/model/touch-up-kit.model.ts new file mode 100644 index 0000000..df625e5 --- /dev/null +++ b/src/app/modules/shared/model/touch-up-kit.model.ts @@ -0,0 +1,24 @@ +export class TouchUpKit { + constructor( + public id: number, + public project: string, + public buggy: string, + public company: string, + public quantity: number, + public shippingDate: string, + public finish: string[], + public material: string[], + public content: TouchUpKitProduct[] + ) { + } +} + +export class TouchUpKitProduct { + constructor( + public id: number, + public name: string, + public description: string | null, + public quantity: number + ) { + } +} diff --git a/src/app/modules/shared/shared.module.ts b/src/app/modules/shared/shared.module.ts index b1391c7..1d7d62e 100644 --- a/src/app/modules/shared/shared.module.ts +++ b/src/app/modules/shared/shared.module.ts @@ -32,10 +32,13 @@ import {MatSliderModule} from '@angular/material/slider' import {SliderFieldComponent} from './components/slider-field/slider-field.component' import {LoadingWheelComponent} from './components/loading-wheel/loading-wheel.component' import {MatProgressSpinnerModule} from '@angular/material/progress-spinner' - +import {InfoBannerModule} from './components/info-banner/info-banner.module' +import {CreFormsModule} from './components/forms/forms.module' +import {VarDirective} from './directives/var.directive' +import {CreColorPreview} from './components/color-preview/color-preview' @NgModule({ - declarations: [HeaderComponent, UserMenuComponent, LabeledIconComponent, ConfirmBoxComponent, PermissionsListComponent, PermissionsFieldComponent, NavComponent, EntityListComponent, EntityAddComponent, EntityEditComponent, FileButtonComponent, GlobalAlertHandlerComponent, SliderFieldComponent, LoadingWheelComponent], + declarations: [VarDirective, HeaderComponent, UserMenuComponent, LabeledIconComponent, ConfirmBoxComponent, PermissionsListComponent, PermissionsFieldComponent, NavComponent, EntityListComponent, EntityAddComponent, EntityEditComponent, FileButtonComponent, GlobalAlertHandlerComponent, SliderFieldComponent, LoadingWheelComponent, CreColorPreview], exports: [ CommonModule, HttpClientModule, @@ -64,7 +67,11 @@ import {MatProgressSpinnerModule} from '@angular/material/progress-spinner' FileButtonComponent, GlobalAlertHandlerComponent, LoadingWheelComponent, - RouterModule + RouterModule, + InfoBannerModule, + CreFormsModule, + VarDirective, + CreColorPreview ], imports: [ MatTabsModule, diff --git a/src/app/modules/shared/utils/utils.ts b/src/app/modules/shared/utils/utils.ts index 266f1e1..e9eaab1 100644 --- a/src/app/modules/shared/utils/utils.ts +++ b/src/app/modules/shared/utils/utils.ts @@ -1,4 +1,8 @@ /** Returns [value] if it is not null or [or]. */ +import {DateTimeFormatter, LocalDate} from 'js-joda' +import {TouchUpKit} from '../model/touch-up-kit.model' +import {environment} from '../../../../environments/environment' + export function valueOr(value: T, or: T): T { return value ? value : or } @@ -14,7 +18,27 @@ export function openJpg(url: string) { openUrl(url, MEDIA_TYPE_JPG) } -function openUrl(url: string, mediaType: string) { - const encodedUrl = `${url}&mediaType=${encodeURIComponent(mediaType)}` - window.open(encodedUrl, '_blank') +export function openTouchUpKit(touchUpKit: TouchUpKit) { + openRawUrl(`${environment.apiUrl}/touchupkit/pdf?project=${touchUpKit.project}`) +} + +export function openUrl(url: string, mediaType: string) { + openRawUrl(`${url}&mediaType=${encodeURIComponent(mediaType)}`) +} + +export function openRawUrl(url: string) { + window.open(url, '_blank') +} + +const dateFormatter = DateTimeFormatter + .ofPattern('dd-MM-yyyy') + +export function formatDate(date: string): string { + return LocalDate.parse(date).format(dateFormatter) +} + +export function reduceDashes(arr: string[]): string { + return arr.reduce((acc, cur) => { + return `${acc} - ${cur}` + }) } diff --git a/src/app/modules/touch-up-kit/components/finish.html b/src/app/modules/touch-up-kit/components/finish.html new file mode 100644 index 0000000..18e7dbd --- /dev/null +++ b/src/app/modules/touch-up-kit/components/finish.html @@ -0,0 +1,11 @@ +
+
{{finish}}
+
+ + + {{recipe.name}} - {{recipe.company.name}} + + + +
+
diff --git a/src/app/modules/touch-up-kit/components/finish.sass b/src/app/modules/touch-up-kit/components/finish.sass new file mode 100644 index 0000000..899e060 --- /dev/null +++ b/src/app/modules/touch-up-kit/components/finish.sass @@ -0,0 +1,28 @@ +@import '~src/custom-theme' + +.touchupkit-finish-container + display: inline-block + position: relative + +.matching + text-decoration: underline + +.matching-recipes + position: absolute + top: 1.5em + transform: translateX(-25%) + width: max-content + display: inline-block + background-color: white + color: $dark-primary-text + border-radius: 4px + +mat-list + padding-top: 0 + +mat-list-item:hover + background-color: darken(white, 5%) + cursor: pointer + +cre-color-preview + display: inline-block diff --git a/src/app/modules/touch-up-kit/components/finish.ts b/src/app/modules/touch-up-kit/components/finish.ts new file mode 100644 index 0000000..d91f01b --- /dev/null +++ b/src/app/modules/touch-up-kit/components/finish.ts @@ -0,0 +1,42 @@ +import {Component, Input} from '@angular/core' +import {SubscribingComponent} from '../../shared/components/subscribing.component' +import {RecipeService} from '../../colors/services/recipe.service' +import {ErrorService} from '../../shared/service/error.service' +import {ActivatedRoute, Router} from '@angular/router' +import {Recipe} from '../../shared/model/recipe.model' + +@Component({ + selector: 'touchupkit-finish', + templateUrl: 'finish.html', + styleUrls: ['finish.sass'] +}) +export class TouchUpKitFinish extends SubscribingComponent { + @Input() finish: string + + hover = false + matchesRecipes = false + matchingRecipes: Recipe[] | null + + constructor( + private recipeService: RecipeService, + errorService: ErrorService, + router: Router, + activatedRoute: ActivatedRoute + ) { + super(errorService, activatedRoute, router) + } + + ngOnInit(): void { + this.subscribe( + this.recipeService.getAllByName(this.finish), + recipes => { + this.matchesRecipes = recipes.length > 0 + this.matchingRecipes = recipes + } + ) + } + + openRecipe(recipe: Recipe) { + window.open(`/color/explore/${recipe.id}`, '_blank') + } +} diff --git a/src/app/modules/touch-up-kit/components/form.html b/src/app/modules/touch-up-kit/components/form.html new file mode 100644 index 0000000..999b820 --- /dev/null +++ b/src/app/modules/touch-up-kit/components/form.html @@ -0,0 +1,34 @@ + + Ajouter un kit de retouche + + + + + + + + La quantité doit être supérieure ou égale à 1 + + + + + + + + + + + diff --git a/src/app/modules/touch-up-kit/components/form.ts b/src/app/modules/touch-up-kit/components/form.ts new file mode 100644 index 0000000..6340f72 --- /dev/null +++ b/src/app/modules/touch-up-kit/components/form.ts @@ -0,0 +1,92 @@ +import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core' +import {chipListRequired, ComboBoxEntry, CreChipComboBoxComponent} from '../../shared/components/inputs/inputs' +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 {CompanyService} from '../../company/service/company.service' +import {ErrorService} from '../../shared/service/error.service' +import {ActivatedRoute, Router} from '@angular/router' +import {TouchUpKit, TouchUpKitProduct} from '../../shared/model/touch-up-kit.model' +import {SubscribingComponent} from '../../shared/components/subscribing.component' +import {map} from 'rxjs/operators' + +@Component({ + selector: 'touchupkit-form', + templateUrl: 'form.html' +}) +export class TouchUpKitForm extends SubscribingComponent { + @ViewChild('finishInput') finishInput: CreChipComboBoxComponent + @ViewChild('materialInput') materialInput: CreChipComboBoxComponent + @ViewChild(CreFormComponent) form: CreFormComponent + @ViewChild(TouchUpKitProductEditor) contentEditor: TouchUpKitProductEditor + + @Input() touchUpKit: TouchUpKit | null + + controls: any + finish$ = this.recipeService.all.pipe( + map(recipes => recipes.map(recipe => new ComboBoxEntry(recipe.id, recipe.name, `${recipe.name} - ${recipe.company.name}`))) + ) + companies$ = this.companyService.all.pipe( + map(companies => companies.map(company => company.name)) + ) + + @Output() submitForm = new EventEmitter() + + constructor( + private recipeService: RecipeService, + private companyService: CompanyService, + errorService: ErrorService, + activatedRoute: ActivatedRoute, + router: Router, + ) { + super(errorService, activatedRoute, router) + } + + ngOnInit() { + super.ngOnInit() + + this.controls = { + project: new FormControl(this.touchUpKit?.project, Validators.required), + buggy: new FormControl(this.touchUpKit?.buggy, Validators.required), + company: new FormControl(this.touchUpKit?.company, Validators.required), + quantity: new FormControl(this.touchUpKit?.quantity, Validators.compose([Validators.required, Validators.min(1)])), + shippingDate: new FormControl(this.touchUpKit?.shippingDate, Validators.required), + finish: new FormControl(this.touchUpKit?.finish, chipListRequired()), + material: new FormControl(this.touchUpKit?.material, chipListRequired()) + } + } + + submit() { + this.submitForm.emit({ + id: this.touchUpKit ? this.touchUpKit.id : null, + project: this.controls.project.value, + buggy: this.controls.buggy.value, + company: this.controls.company.value, + quantity: this.controls.quantity.value, + shippingDate: this.controls.shippingDate.value, + finish: this.selectedFinish, + material: this.selectedMaterial, + content: this.touchUpKitContent + }) + } + + get selectedFinish(): string[] { + return this.finishInput.selectedValues + } + + get selectedMaterial(): string[] { + return this.materialInput.selectedValues + } + + get touchUpKitContent(): TouchUpKitProduct[] { + return this.contentEditor.products + } + + get formValid(): boolean { + return this.form && !this.form.invalid && + !this.finishInput.empty && + !this.materialInput.empty && + !this.contentEditor.empty + } +} diff --git a/src/app/modules/touch-up-kit/components/product-editor.html b/src/app/modules/touch-up-kit/components/product-editor.html new file mode 100644 index 0000000..477335b --- /dev/null +++ b/src/app/modules/touch-up-kit/components/product-editor.html @@ -0,0 +1,55 @@ + + + Contenu + + + + + + + + + + + + + + + + + + + + + + + + + + +
Nom + + + {{product.name}} + + Description + + + {{product.description ? product.description : '-'}} + + Quantité + + + {{product.quantity}} + + + Ajouter + + Retirer +
+
+
diff --git a/src/app/modules/touch-up-kit/components/product-editor.sass b/src/app/modules/touch-up-kit/components/product-editor.sass new file mode 100644 index 0000000..eaad423 --- /dev/null +++ b/src/app/modules/touch-up-kit/components/product-editor.sass @@ -0,0 +1,25 @@ +@import '../../../../custom-theme' + +touchupkit-product-editor + .mat-form-field-label-wrapper + opacity: 0 + + cre-input, span.focused + display: inline-block + width: 15rem + + span.focused + white-space: nowrap + overflow: hidden + + // Content card + mat-card-content + margin: 0 + padding: 0 + + table + border: none + box-shadow: none + + th + border-radius: 0 !important diff --git a/src/app/modules/touch-up-kit/components/product-editor.ts b/src/app/modules/touch-up-kit/components/product-editor.ts new file mode 100644 index 0000000..ea2d840 --- /dev/null +++ b/src/app/modules/touch-up-kit/components/product-editor.ts @@ -0,0 +1,57 @@ +import {Component, Input, OnInit, ViewChild, ViewEncapsulation} from '@angular/core' +import {TouchUpKitProduct} from '../../shared/model/touch-up-kit.model' +import {MatTable} from '@angular/material/table' + +@Component({ + selector: 'touchupkit-product-editor', + templateUrl: 'product-editor.html', + styleUrls: ['product-editor.sass'], + encapsulation: ViewEncapsulation.None +}) +export class TouchUpKitProductEditor implements OnInit { + productCols = ['name', 'description', 'quantity', 'removeButton'] + + @Input() products: TouchUpKitProduct[] + + @ViewChild(MatTable) table: MatTable + hoveredProduct: TouchUpKitProduct | null + selectedProduct: TouchUpKitProduct | null + + ngOnInit(): void { + if (!this.products) { + this.products = [this.emptyProduct] + } + } + + addRow() { + const newProduct = this.emptyProduct + + this.products.push(newProduct) + this.table.renderRows() + this.selectedProduct = newProduct + } + + removeRow(product: TouchUpKitProduct) { + this.products = this.products.filter(p => p !== product) + this.table.renderRows() + } + + isFocused(index: number, product: TouchUpKitProduct): boolean { + return (!this.hoveredProduct && index === 0) || + this.hoveredProduct === product || + this.selectedProduct === product + } + + get empty(): boolean { + return this.products.length <= 0 + } + + get emptyProduct(): TouchUpKitProduct { + return { + id: null, + name: '', + description: '', + quantity: 1 + } + } +} diff --git a/src/app/modules/touch-up-kit/pages/add.html b/src/app/modules/touch-up-kit/pages/add.html new file mode 100644 index 0000000..be52732 --- /dev/null +++ b/src/app/modules/touch-up-kit/pages/add.html @@ -0,0 +1,11 @@ + + + Retour + + + Enregistrer + + + + + diff --git a/src/app/modules/touch-up-kit/pages/banner.html b/src/app/modules/touch-up-kit/pages/banner.html new file mode 100644 index 0000000..4da19bc --- /dev/null +++ b/src/app/modules/touch-up-kit/pages/banner.html @@ -0,0 +1,19 @@ + + {{touchUpKit.project}} - {{touchUpKit.company}} + + +

Chariot: {{touchUpKit.buggy}}

+

Quantité: {{touchUpKit.quantity}}

+

Date de livraison: {{shippingDate}}

+
+ +

Fini: + + + - + +

+

Matériel: {{material}}

+
+
+
diff --git a/src/app/modules/touch-up-kit/pages/details.html b/src/app/modules/touch-up-kit/pages/details.html new file mode 100644 index 0000000..99bbb6c --- /dev/null +++ b/src/app/modules/touch-up-kit/pages/details.html @@ -0,0 +1,28 @@ +
+ + +
+ + +
+ + + + Nom + {{product.name}} + + + + Description + + {{product.description}} + - + + + + + Quantité + {{product.quantity}} + + +
diff --git a/src/app/modules/touch-up-kit/pages/details.sass b/src/app/modules/touch-up-kit/pages/details.sass new file mode 100644 index 0000000..caf74e0 --- /dev/null +++ b/src/app/modules/touch-up-kit/pages/details.sass @@ -0,0 +1,2 @@ +info-banner-section p + margin-bottom: 0 diff --git a/src/app/modules/touch-up-kit/pages/edit.html b/src/app/modules/touch-up-kit/pages/edit.html new file mode 100644 index 0000000..7fd4938 --- /dev/null +++ b/src/app/modules/touch-up-kit/pages/edit.html @@ -0,0 +1,24 @@ + + + + Retour + + + Supprimer + Enregistrer + + + + + + + + + + diff --git a/src/app/modules/touch-up-kit/pages/list.html b/src/app/modules/touch-up-kit/pages/list.html new file mode 100644 index 0000000..e5fc496 --- /dev/null +++ b/src/app/modules/touch-up-kit/pages/list.html @@ -0,0 +1,53 @@ + + + + Ajouter + + + + + + Project + {{touchUpKit.project}} + + + + Chariot + {{touchUpKit.buggy}} + + + + Bannière + {{touchUpKit.company}} + + + + Date de livraison + {{touchUpKit.shippingDate}} + + + + + + PDF + + + + + + + + Détails + + + + + + + + + Modifier + + + + diff --git a/src/app/modules/touch-up-kit/pages/touchupkit.ts b/src/app/modules/touch-up-kit/pages/touchupkit.ts new file mode 100644 index 0000000..a050397 --- /dev/null +++ b/src/app/modules/touch-up-kit/pages/touchupkit.ts @@ -0,0 +1,152 @@ +import {Component, Input} from '@angular/core' +import {TouchUpKit} from '../../shared/model/touch-up-kit.model' +import {formatDate, openTouchUpKit, reduceDashes} from '../../shared/utils/utils' +import {ErrorHandlingComponent} from '../../shared/components/subscribing.component' +import {TouchUpKitService} from '../service/touch-up-kit.service' +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' + +@Component({ + selector: 'touchupkit-banner', + templateUrl: 'banner.html', + styles: [ + 'p { margin-bottom: 0 }' + ] +}) +export class TouchUpKitBanner { + @Input() touchUpKit: TouchUpKit + + get shippingDate(): string { + return formatDate(this.touchUpKit.shippingDate) + } + + get material(): string { + return reduceDashes(this.touchUpKit.material) + } +} + +@Component({ + selector: 'touchupkit-list', + templateUrl: './list.html' +}) +export class TouchUpKitList extends ErrorHandlingComponent { + touchUpKits$ = this.touchUpKitService.all + columns = ['project', 'buggy', 'company', 'shippingDate', 'pdfButton', 'detailsButton', 'editButton'] + + constructor( + private touchUpKitService: TouchUpKitService, + private accountService: AccountService, + errorService: ErrorService, + router: Router, + activatedRoute: ActivatedRoute + ) { + super(errorService, activatedRoute, router) + } + + openTouchUpKitPdf(touchUpKit: TouchUpKit) { + openTouchUpKit(touchUpKit) + } + + get canEditTouchUpKits(): boolean { + return this.accountService.hasPermission(Permission.EDIT_TOUCH_UP_KITS) + } +} + +@Component({ + selector: 'touchupkit-details', + templateUrl: 'details.html' +}) +export class TouchUpKitDetails extends ErrorHandlingComponent { + touchUpKit: TouchUpKit | null + contentTableCols = ['name', 'description', 'quantity'] + + constructor( + private touchUpKitService: TouchUpKitService, + private recipeService: RecipeService, + errorService: ErrorService, + activatedRoute: ActivatedRoute, + router: Router + ) { + super(errorService, activatedRoute, router) + } + + ngOnInit() { + super.ngOnInit() + + this.subscribeEntityById( + this.touchUpKitService, + this.urlUtils.parseIntUrlParam('id'), + t => this.touchUpKit = t + ) + } + + openPdf() { + openTouchUpKit(this.touchUpKit) + } +} + +@Component({ + selector: 'touchupkit-add', + templateUrl: 'add.html' +}) +export class TouchUpKitAdd extends ErrorHandlingComponent { + constructor( + private touchUpKitService: TouchUpKitService, + errorService: ErrorService, + activatedRoute: ActivatedRoute, + router: Router, + ) { + super(errorService, activatedRoute, router) + } + + submit(touchUpKit) { + this.subscribeAndNavigate( + this.touchUpKitService.save(touchUpKit), + '/misc/touch-up-kit/list' + ) + } +} + +@Component({ + selector: 'touchupkit-edit', + templateUrl: 'edit.html' +}) +export class TouchUpKitEdit extends ErrorHandlingComponent { + touchUpKit: TouchUpKit | null + + constructor( + private touchUpKitService: TouchUpKitService, + errorService: ErrorService, + activatedRoute: ActivatedRoute, + router: Router + ) { + super(errorService, activatedRoute, router) + } + + ngOnInit() { + super.ngOnInit() + + this.subscribeEntityById( + this.touchUpKitService, + this.urlUtils.parseIntUrlParam('id'), + touchUpKit => this.touchUpKit = touchUpKit + ) + } + + submit(touchUpKit) { + this.subscribeAndNavigate( + this.touchUpKitService.update(touchUpKit), + '/misc/touch-up-kit/list' + ) + } + + delete() { + this.subscribeAndNavigate( + this.touchUpKitService.delete(this.touchUpKit.id), + '/misc/touch-up-kit/list' + ) + } +} diff --git a/src/app/modules/touch-up-kit/service/touch-up-kit.service.ts b/src/app/modules/touch-up-kit/service/touch-up-kit.service.ts new file mode 100644 index 0000000..18aa7b2 --- /dev/null +++ b/src/app/modules/touch-up-kit/service/touch-up-kit.service.ts @@ -0,0 +1,34 @@ +import {Injectable} from '@angular/core' +import {ApiService} from '../../shared/service/api.service' +import {Observable} from 'rxjs' +import {TouchUpKit, TouchUpKitProduct} from '../../shared/model/touch-up-kit.model' + +@Injectable({ + providedIn: 'root' +}) +export class TouchUpKitService { + constructor( + private api: ApiService + ) { + } + + get all(): Observable { + return this.api.get('/touchupkit') + } + + getById(id: number): Observable { + return this.api.get(`/touchupkit/${id}`) + } + + save(touchUpKit: TouchUpKit): Observable { + return this.api.post('/touchupkit', touchUpKit) + } + + update(touchUpKit: TouchUpKit): Observable { + return this.api.put('/touchupkit', touchUpKit) + } + + delete(id: number): Observable { + return this.api.delete(`/touchupkit/${id}`) + } +} diff --git a/src/app/modules/touch-up-kit/touch-up-kit-routing.module.ts b/src/app/modules/touch-up-kit/touch-up-kit-routing.module.ts new file mode 100644 index 0000000..ce570bf --- /dev/null +++ b/src/app/modules/touch-up-kit/touch-up-kit-routing.module.ts @@ -0,0 +1,28 @@ +import {NgModule} from '@angular/core' +import {RouterModule, Routes} from '@angular/router' +import {TouchUpKitAdd, TouchUpKitDetails, TouchUpKitEdit, TouchUpKitList} from './pages/touchupkit' + +const routes: Routes = [{ + path: 'list', + component: TouchUpKitList +}, { + path: 'details/:id', + component: TouchUpKitDetails +}, { + path: 'add', + component: TouchUpKitAdd +}, { + path: 'edit/:id', + component: TouchUpKitEdit +}, { + path: '', + pathMatch: 'full', + redirectTo: 'list' +}] + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class TouchUpKitRoutingModule { +} diff --git a/src/app/modules/touch-up-kit/touch-up-kit.module.ts b/src/app/modules/touch-up-kit/touch-up-kit.module.ts new file mode 100644 index 0000000..067f3d4 --- /dev/null +++ b/src/app/modules/touch-up-kit/touch-up-kit.module.ts @@ -0,0 +1,41 @@ +import {NgModule} from '@angular/core' +import {CommonModule} from '@angular/common' +import {TouchUpKitRoutingModule} from './touch-up-kit-routing.module' +import {SharedModule} from '../shared/shared.module' +import {CreInputsModule} from '../shared/components/inputs/inputs.module' +import {CreButtonsModule} from '../shared/components/buttons/buttons.module' +import {TouchUpKitProductEditor} from './components/product-editor' +import {FormsModule} from '@angular/forms' +import {CreActionBarModule} from '../shared/components/action-bar/action-bar.module' +import {TouchUpKitForm} from './components/form' +import {CreTablesModule} from '../shared/components/tables/tables.module' +import {TouchUpKitAdd, TouchUpKitBanner, TouchUpKitDetails, TouchUpKitEdit, TouchUpKitList} from './pages/touchupkit' +import {TouchUpKitFinish} from './components/finish' +import {MatTooltipModule} from '@angular/material/tooltip' + + +@NgModule({ + declarations: [ + TouchUpKitForm, + TouchUpKitProductEditor, + TouchUpKitBanner, + TouchUpKitFinish, + TouchUpKitList, + TouchUpKitDetails, + TouchUpKitAdd, + TouchUpKitEdit + ], + imports: [ + CommonModule, + TouchUpKitRoutingModule, + SharedModule, + CreInputsModule, + CreButtonsModule, + FormsModule, + CreActionBarModule, + CreTablesModule, + MatTooltipModule + ] +}) +export class TouchUpKitModule { +} diff --git a/src/app/pages/others/misc.component.ts b/src/app/pages/others/misc.component.ts index fe3f2c9..03d63a8 100644 --- a/src/app/pages/others/misc.component.ts +++ b/src/app/pages/others/misc.component.ts @@ -10,6 +10,6 @@ import {Permission} from '../../modules/shared/model/user' }) export class MiscComponent extends SubMenuComponent{ links: NavLink[] = [ - {route: '/misc/touchupkit', title: 'Kits de retouche', permission: Permission.VIEW_TOUCH_UP_KITS} + {route: '/misc/touch-up-kit', title: 'Kits de retouche', permission: Permission.VIEW_TOUCH_UP_KITS} ] } diff --git a/src/app/pages/others/touchupkit/touchupkit.component.html b/src/app/pages/others/touchupkit/touchupkit.component.html deleted file mode 100644 index 0218a25..0000000 --- a/src/app/pages/others/touchupkit/touchupkit.component.html +++ /dev/null @@ -1,23 +0,0 @@ - - - Génération d'un kit de retouche - - -
- - Job - - - -
-
- - - -
diff --git a/src/app/pages/others/touchupkit/touchupkit.component.sass b/src/app/pages/others/touchupkit/touchupkit.component.sass deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/pages/others/touchupkit/touchupkit.component.ts b/src/app/pages/others/touchupkit/touchupkit.component.ts deleted file mode 100644 index 1ffe1e8..0000000 --- a/src/app/pages/others/touchupkit/touchupkit.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {Component, OnInit} from '@angular/core' -import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms' -import {TouchupkitService} from '../../../modules/shared/service/touchupkit.service' - -@Component({ - selector: 'cre-touchupkit', - templateUrl: './touchupkit.component.html', - styleUrls: ['./touchupkit.component.sass'] -}) -export class TouchupkitComponent implements OnInit { - formGroup: FormGroup - jobControl: FormControl - - constructor( - private touchUpKitService: TouchupkitService, - private formBuilder: FormBuilder - ) { - } - - ngOnInit(): void { - this.jobControl = new FormControl(null, Validators.required) - this.formGroup = this.formBuilder.group({ - job: this.jobControl - }) - } - - submit() { - this.touchUpKitService.generateJobPdfDocument(this.jobControl.value) - } -} diff --git a/src/styles.sass b/src/styles.sass index 146b03d..5570317 100644 --- a/src/styles.sass +++ b/src/styles.sass @@ -5,7 +5,6 @@ mat-card padding: 0 !important width: max-content - max-width: 50rem &.x-centered margin: auto @@ -168,27 +167,6 @@ div.empty margin-left: 0 margin-right: 1rem -.recipe-color-circle - color: black - width: 2.2rem - height: 2.2rem - border-radius: 1.1rem - margin-left: 1rem - font-size: 13px - - &.dark-mode - color: white - width: 2.3rem - height: 2.3rem - border: solid 1px white - - div - position: absolute - width: 2rem - text-align: center - margin-top: 7px - margin-left: 1px - .alert p margin-bottom: 0