table and new product

This commit is contained in:
Tizian.Breuch
2025-10-29 11:50:48 +01:00
parent 4549149e48
commit 05bedfedfb
6 changed files with 117 additions and 30 deletions

View File

@@ -3,12 +3,18 @@
import { Component, OnInit, inject } from '@angular/core';
import { Router } from '@angular/router';
import { CommonModule, CurrencyPipe, DatePipe } from '@angular/common';
import { AdminProduct, ProductImage } from '../../../../core/models/product.model';
import {
AdminProduct,
ProductImage,
} from '../../../../core/models/product.model';
import { ProductService } from '../../../services/product.service';
import { SupplierService } from '../../../services/supplier.service';
import { SnackbarService } from '../../../../shared/services/snackbar.service';
import { StorageService } from '../../../../core/services/storage.service';
import { GenericTableComponent, ColumnConfig } from '../../../../shared/components/data-display/generic-table/generic-table.component';
import {
GenericTableComponent,
ColumnConfig,
} from '../../../../shared/components/data-display/generic-table/generic-table.component';
import { SearchBarComponent } from '../../../../shared/components/layout/search-bar/search-bar.component';
import { ButtonComponent } from '../../../../shared/components/ui/button/button.component';
import { IconComponent } from '../../../../shared/components/ui/icon/icon.component';
@@ -16,10 +22,18 @@ import { IconComponent } from '../../../../shared/components/ui/icon/icon.compon
@Component({
selector: 'app-product-list',
standalone: true,
imports: [CommonModule, CurrencyPipe, DatePipe, GenericTableComponent, SearchBarComponent, ButtonComponent, IconComponent],
imports: [
CommonModule,
CurrencyPipe,
DatePipe,
GenericTableComponent,
SearchBarComponent,
ButtonComponent,
IconComponent,
],
providers: [DatePipe],
templateUrl: './product-list.component.html',
styleUrl: './product-list.component.css'
styleUrl: './product-list.component.css',
})
export class ProductListComponent implements OnInit {
private productService = inject(ProductService);
@@ -28,21 +42,65 @@ export class ProductListComponent implements OnInit {
private snackbar = inject(SnackbarService);
private storageService = inject(StorageService);
private datePipe = inject(DatePipe);
private readonly TABLE_SETTINGS_KEY = 'product-table-columns';
allProducts: (AdminProduct & { mainImage?: string; supplierName?: string })[] = [];
filteredProducts: (AdminProduct & { mainImage?: string; supplierName?: string })[] = [];
allProducts: (AdminProduct & {
mainImage?: string;
supplierName?: string;
})[] = [];
filteredProducts: (AdminProduct & {
mainImage?: string;
supplierName?: string;
})[] = [];
isColumnFilterVisible = false;
readonly allTableColumns: ColumnConfig[] = [
{ key: 'mainImage', title: 'Bild', type: 'image' },
{ key: 'name', title: 'Name', type: 'text', subKey: 'sku' },
{ key: 'price', title: 'Preis', type: 'currency', cssClass: 'text-right' },
{ key: 'stockQuantity', title: 'Lager', type: 'text', cssClass: 'text-right' },
{
key: 'stockQuantity',
title: 'Lager',
type: 'text',
cssClass: 'text-right',
},
{ key: 'supplierName', title: 'Lieferant', type: 'text' },
{ key: 'isActive', title: 'Aktiv', type: 'status' },
{ key: 'actions', title: 'Aktionen', type: 'actions', cssClass: 'text-right' }
{ key: 'id', title: 'ID', type: 'text' },
{ key: 'description', title: 'Beschreibung', type: 'text' },
{
key: 'oldPrice',
title: 'Alter Preis',
type: 'currency',
cssClass: 'text-right',
},
{
key: 'purchasePrice',
title: 'Einkaufspreis',
type: 'currency',
cssClass: 'text-right',
},
{ key: 'isInStock', title: 'Auf Lager', type: 'status' },
{ key: 'weight', title: 'Gewicht', type: 'number', cssClass: 'text-right' },
{ key: 'slug', title: 'Slug', type: 'text' },
{ key: 'createdDate', title: 'Erstellt am', type: 'date' },
{ key: 'lastModifiedDate', title: 'Zuletzt geändert', type: 'date' },
{ key: 'supplierId', title: 'Lieferanten-ID', type: 'text' },
{ key: 'categorieIds', title: 'Kategorie-IDs', type: 'text' },
{ key: 'isFeatured', title: 'Hervorgehoben', type: 'status' },
{
key: 'featuredDisplayOrder',
title: 'Anzeigereihenfolge (hervorgehoben)',
type: 'number',
cssClass: 'text-right',
},
{
key: 'actions',
title: 'Aktionen',
type: 'actions',
cssClass: 'text-right',
},
];
visibleTableColumns: ColumnConfig[] = [];
@@ -55,15 +113,16 @@ export class ProductListComponent implements OnInit {
}
loadProducts(): void {
this.productService.getAll().subscribe(products => {
this.supplierService.getAll().subscribe(suppliers => {
this.allProducts = products.map(p => {
const supplier = suppliers.find(s => s.id === p.supplierId);
this.productService.getAll().subscribe((products) => {
this.supplierService.getAll().subscribe((suppliers) => {
this.allProducts = products.map((p) => {
const supplier = suppliers.find((s) => s.id === p.supplierId);
return {
...p,
mainImage: this.getMainImageUrl(p.images),
supplierName: supplier?.name || '-',
createdDate: this.datePipe.transform(p.createdDate, 'dd.MM.yyyy HH:mm') || '-',
createdDate:
this.datePipe.transform(p.createdDate, 'dd.MM.yyyy HH:mm') || '-',
};
});
this.onSearch('');
@@ -73,9 +132,10 @@ export class ProductListComponent implements OnInit {
onSearch(term: string): void {
const lowerTerm = term.toLowerCase();
this.filteredProducts = this.allProducts.filter(p =>
p.name?.toLowerCase().includes(lowerTerm) ||
p.sku?.toLowerCase().includes(lowerTerm)
this.filteredProducts = this.allProducts.filter(
(p) =>
p.name?.toLowerCase().includes(lowerTerm) ||
p.sku?.toLowerCase().includes(lowerTerm)
);
}
@@ -97,14 +157,26 @@ export class ProductListComponent implements OnInit {
}
private loadTableSettings(): void {
const savedKeys = this.storageService.getItem<string[]>(this.TABLE_SETTINGS_KEY);
const defaultKeys = ['mainImage', 'name', 'price', 'stockQuantity', 'isActive', 'actions'];
const keysToUse = (savedKeys && savedKeys.length > 0) ? savedKeys : defaultKeys;
this.visibleTableColumns = this.allTableColumns.filter(c => keysToUse.includes(c.key));
const savedKeys = this.storageService.getItem<string[]>(
this.TABLE_SETTINGS_KEY
);
const defaultKeys = [
'mainImage',
'name',
'price',
'stockQuantity',
'isActive',
'actions',
];
const keysToUse =
savedKeys && savedKeys.length > 0 ? savedKeys : defaultKeys;
this.visibleTableColumns = this.allTableColumns.filter((c) =>
keysToUse.includes(c.key)
);
}
private saveTableSettings(): void {
const visibleKeys = this.visibleTableColumns.map(c => c.key);
const visibleKeys = this.visibleTableColumns.map((c) => c.key);
this.storageService.setItem(this.TABLE_SETTINGS_KEY, visibleKeys);
}
@@ -113,26 +185,29 @@ export class ProductListComponent implements OnInit {
}
isColumnVisible(columnKey: string): boolean {
return this.visibleTableColumns.some(c => c.key === columnKey);
return this.visibleTableColumns.some((c) => c.key === columnKey);
}
onColumnToggle(column: ColumnConfig, event: Event): void {
const checkbox = event.target as HTMLInputElement;
if (checkbox.checked) {
this.visibleTableColumns.push(column);
this.visibleTableColumns.sort((a, b) =>
this.allTableColumns.findIndex(c => c.key === a.key) -
this.allTableColumns.findIndex(c => c.key === b.key)
this.visibleTableColumns.sort(
(a, b) =>
this.allTableColumns.findIndex((c) => c.key === a.key) -
this.allTableColumns.findIndex((c) => c.key === b.key)
);
} else {
this.visibleTableColumns = this.visibleTableColumns.filter(c => c.key !== column.key);
this.visibleTableColumns = this.visibleTableColumns.filter(
(c) => c.key !== column.key
);
}
this.saveTableSettings();
}
getMainImageUrl(images?: ProductImage[]): string {
if (!images || images.length === 0) return 'https://via.placeholder.com/50';
const mainImage = images.find(img => img.isMainImage);
const mainImage = images.find((img) => img.isMainImage);
return mainImage?.url || images[0]?.url || 'https://via.placeholder.com/50';
}
}
}

View File

@@ -0,0 +1 @@
<p>product-new works!</p>

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-product-new',
imports: [],
templateUrl: './product-new.component.html',
styleUrl: './product-new.component.css'
})
export class ProductNewComponent {
}

View File

@@ -6,7 +6,7 @@ import { StatusPillComponent } from '../../ui/status-pill/status-pill.component'
import { ButtonComponent } from '../../ui/button/button.component';
import { PaginatorComponent } from '../paginator/paginator.component';
export type ColumnType = 'text' | 'currency' | 'status' | 'image-text' | 'image' | 'actions';
export type ColumnType = 'text' | 'currency' | 'status' | 'image-text' | 'image' | 'actions' | 'date' | 'number';
export interface ColumnConfig {
key: string;