- - -

Allgemein

-
- - - + + - - + + + + + + - - - -
-
+ + + +
+ +
+ + +
+ +
- - - +
Abbrechen - - {{ submitButtonText }} - + {{ submitButtonText }}
\ No newline at end of file diff --git a/src/app/features/components/products/product-form/product-form.component.ts b/src/app/features/components/products/product-form/product-form.component.ts index fa3f55b..7f34caa 100644 --- a/src/app/features/components/products/product-form/product-form.component.ts +++ b/src/app/features/components/products/product-form/product-form.component.ts @@ -1,31 +1,43 @@ // /src/app/features/admin/components/products/product-form/product-form.component.ts -import { Component, Input, Output, EventEmitter, inject, OnChanges, SimpleChanges } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { FormGroup, FormArray, ReactiveFormsModule, FormControl } from '@angular/forms'; +import { Component, Input, Output, EventEmitter, inject } from '@angular/core'; +import { CommonModule, NgClass } from '@angular/common'; +import { + FormGroup, + FormArray, + ReactiveFormsModule, + FormControl, +} from '@angular/forms'; import { SafeUrl } from '@angular/platform-browser'; -// Models -import { ProductImage } from '../../../../core/models/product.model'; +// Models & UI Components import { Category } from '../../../../core/models/category.model'; - -// Services -import { SnackbarService } from '../../../../shared/services/snackbar.service'; - -// UI Components import { CardComponent } from '../../../../shared/components/ui/card/card.component'; import { ButtonComponent } from '../../../../shared/components/ui/button/button.component'; import { IconComponent } from '../../../../shared/components/ui/icon/icon.component'; import { FormFieldComponent } from '../../../../shared/components/form/form-field/form-field.component'; -import { FormSelectComponent, SelectOption } from '../../../../shared/components/form/form-select/form-select.component'; +import { + FormSelectComponent, + SelectOption, +} from '../../../../shared/components/form/form-select/form-select.component'; import { FormTextareaComponent } from '../../../../shared/components/form/form-textarea/form-textarea.component'; import { SlideToggleComponent } from '../../../../shared/components/form/slide-toggle/slide-toggle.component'; +import { SnackbarService } from '../../../../shared/services/snackbar.service'; +import { FormGroupComponent } from '../../../../shared/components/form/form-group/form-group.component'; + +// Interface für eine einheitliche Bild-Datenstruktur, die von der Elternkomponente kommt +export interface ImagePreview { + identifier: string; // Eindeutiger Bezeichner (ID für existierende, Dateiname für neue) + url: string | SafeUrl; + isMainImage: boolean; +} @Component({ selector: 'app-product-form', standalone: true, imports: [ CommonModule, + NgClass, ReactiveFormsModule, CardComponent, ButtonComponent, @@ -34,69 +46,66 @@ import { SlideToggleComponent } from '../../../../shared/components/form/slide-t FormSelectComponent, FormTextareaComponent, SlideToggleComponent, + FormGroupComponent, ], templateUrl: './product-form.component.html', - styleUrls: ['./product-form.component.css'] + styleUrls: ['./product-form.component.css'], }) export class ProductFormComponent { + // --- Inputs für Daten --- @Input() productForm!: FormGroup; @Input() allCategories: Category[] = []; @Input() supplierOptions: SelectOption[] = []; @Input() isLoading = false; @Input() submitButtonText = 'Speichern'; - - // Inputs & Outputs für Bilder - @Input() existingImages: ProductImage[] = []; - @Input() mainImagePreview: string | SafeUrl | null = null; - @Input() additionalImagesPreview: { name: string, url: string | SafeUrl }[] = []; + // NEU: Empfängt eine einzige, kombinierte Bildliste von der Elternkomponente + @Input() allImages: ImagePreview[] = []; + + // --- Outputs für Aktionen --- @Output() formSubmit = new EventEmitter(); @Output() formCancel = new EventEmitter(); - @Output() mainFileSelected = new EventEmitter(); - @Output() additionalFilesSelected = new EventEmitter(); - @Output() existingImageDeleted = new EventEmitter(); - @Output() newImageRemoved = new EventEmitter(); + @Output() filesSelected = new EventEmitter(); // Sendet alle neu ausgewählten Dateien + @Output() setMainImage = new EventEmitter(); // Sendet den 'identifier' des Bildes + @Output() deleteImage = new EventEmitter(); // Sendet den 'identifier' des Bildes private snackbarService = inject(SnackbarService); // GETTER FÜR DAS TEMPLATE - get categorieIds(): FormArray { return this.productForm.get('categorieIds') as FormArray; } - + get categorieIds(): FormArray { + return this.productForm.get('categorieIds') as FormArray; + } get hasImages(): boolean { - return !!this.mainImagePreview || this.additionalImagesPreview.length > 0 || this.existingImages.length > 0; - } - - // NEU: Getter, der die Filter-Logik aus dem Template entfernt - get additionalExistingImages(): ProductImage[] { - return this.existingImages.filter(image => !image.isMainImage); + return this.allImages && this.allImages.length > 0; } - // FORMULAR-INTERAKTIONEN - onSubmit(): void { this.formSubmit.emit(); } - cancel(): void { this.formCancel.emit(); } - - // BILD-MANAGEMENT - onMainFileChange(event: Event): void { - const file = (event.target as HTMLInputElement).files?.[0]; - if (file) this.mainFileSelected.emit(file); + // --- EVENT-HANDLER --- + onSubmit(): void { + this.formSubmit.emit(); } - - onAdditionalFilesChange(event: Event): void { + cancel(): void { + this.formCancel.emit(); + } + + onFilesSelected(event: Event): void { const files = (event.target as HTMLInputElement).files; - if (files) this.additionalFilesSelected.emit(Array.from(files)); + if (files && files.length > 0) { + this.filesSelected.emit(Array.from(files)); + } + // Wichtig: Input-Wert zurücksetzen, damit die gleichen Dateien erneut ausgewählt werden können + (event.target as HTMLInputElement).value = ''; } - deleteExistingImage(imageId: string, event: Event): void { - event.preventDefault(); - this.existingImageDeleted.emit(imageId); + setAsMainImage(identifier: string): void { + this.setMainImage.emit(identifier); } - removeNewImage(fileName: string, event: Event): void { - event.preventDefault(); - this.newImageRemoved.emit(fileName); + requestImageDeletion(identifier: string, event: MouseEvent): void { + event.stopPropagation(); // Verhindert, dass gleichzeitig setAsMainImage gefeuert wird + this.deleteImage.emit(identifier); } - // KATEGORIE- & SKU-HELFER + // --- Helfermethoden (unverändert) --- generateSku(): void { const name = this.productForm.get('name')?.value || 'PROD'; const prefix = name.substring(0, 4).toUpperCase().replace(/\s+/g, ''); @@ -114,7 +123,9 @@ export class ProductFormComponent { this.categorieIds.push(new FormControl(categoryId)); } } else { - const index = this.categorieIds.controls.findIndex(x => x.value === categoryId); + const index = this.categorieIds.controls.findIndex( + (x) => x.value === categoryId + ); if (index !== -1) this.categorieIds.removeAt(index); } } @@ -124,11 +135,13 @@ export class ProductFormComponent { } getCategoryName(categoryId: string): string { - return this.allCategories.find(c => c.id === categoryId)?.name || ''; + return this.allCategories.find((c) => c.id === categoryId)?.name || ''; } removeCategoryById(categoryId: string): void { - const index = this.categorieIds.controls.findIndex(x => x.value === categoryId); + const index = this.categorieIds.controls.findIndex( + (x) => x.value === categoryId + ); if (index !== -1) this.categorieIds.removeAt(index); } -} \ No newline at end of file +} diff --git a/src/app/shared/components/form/form-group/form-group.component.css b/src/app/shared/components/form/form-group/form-group.component.css index 7696d2b..f939424 100644 --- a/src/app/shared/components/form/form-group/form-group.component.css +++ b/src/app/shared/components/form/form-group/form-group.component.css @@ -23,7 +23,7 @@ font-size: 0.9rem; color: var(--color-text-light); margin-top: -0.75rem; /* Rücken wir näher an den Titel */ - margin-bottom: 1.5rem; + margin-bottom: 1rem; } .form-group-content { diff --git a/src/app/shared/components/form/form-group/form-group.component.html b/src/app/shared/components/form/form-group/form-group.component.html index d6c4290..b625e64 100644 --- a/src/app/shared/components/form/form-group/form-group.component.html +++ b/src/app/shared/components/form/form-group/form-group.component.html @@ -9,12 +9,6 @@ {{ description }}

-