diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts
index 3adbaa1..9937628 100644
--- a/src/app/app.routes.ts
+++ b/src/app/app.routes.ts
@@ -31,7 +31,36 @@ export const routes: Routes = [
{
path: 'auth',
loadChildren: () =>
- import('./features/components/auth/auth.routes').then((r) => r.AUTH_ROUTES),
+ import('./features/components/auth/auth.routes').then(
+ (r) => r.AUTH_ROUTES
+ ),
+ },
+ {
+ path: 'categories',
+ canActivate: [authGuard],
+ data: { requiredRole: 'Admin' },
+ loadChildren: () =>
+ import('./features/components/categories/categories.routes').then(
+ (r) => r.CATEGORIES_ROUTES
+ ),
+ },
+ {
+ path: 'discounts',
+ canActivate: [authGuard],
+ data: { requiredRole: 'Admin' },
+ loadChildren: () =>
+ import('./features/components/discounts/discounts.routes').then(
+ (r) => r.DISCOUNTS_ROUTES
+ ),
+ },
+ {
+ path: 'orders',
+ canActivate: [authGuard],
+ data: { requiredRole: 'Admin' },
+ loadChildren: () =>
+ import('./features/components/orders/orders.routes').then(
+ (r) => r.ORDERS_ROUTES
+ ),
},
{
path: 'access-denied',
diff --git a/src/app/features/components/categories/categories.routes.ts b/src/app/features/components/categories/categories.routes.ts
new file mode 100644
index 0000000..df79860
--- /dev/null
+++ b/src/app/features/components/categories/categories.routes.ts
@@ -0,0 +1,10 @@
+import { Routes } from '@angular/router';
+import { CategoryListComponent } from './category-list/category-list.component';
+
+export const CATEGORIES_ROUTES: Routes = [
+ {
+ path: '',
+ component: CategoryListComponent,
+ title: 'Category Übersicht',
+ },
+];
diff --git a/src/app/features/components/categories/category-list/category-list.component.html b/src/app/features/components/categories/category-list/category-list.component.html
index b49570c..808c2e6 100644
--- a/src/app/features/components/categories/category-list/category-list.component.html
+++ b/src/app/features/components/categories/category-list/category-list.component.html
@@ -1,26 +1,66 @@
Kategorien verwalten
-
-
Bestehende Kategorien
-
+
+
{{ category.name }} (Slug: {{ category.slug }}) - Aktiv: {{ category.isActive }}
diff --git a/src/app/features/components/categories/category-list/category-list.component.ts b/src/app/features/components/categories/category-list/category-list.component.ts
index fc8bce1..4946b5a 100644
--- a/src/app/features/components/categories/category-list/category-list.component.ts
+++ b/src/app/features/components/categories/category-list/category-list.component.ts
@@ -1,7 +1,7 @@
import { Component, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
-import { Observable } from 'rxjs';
+import { Observable, map } from 'rxjs';
import { Category } from '../../../../core/models/category.model';
import { CategoryService } from '../../../services/category.service';
@@ -16,9 +16,14 @@ export class CategoryListComponent implements OnInit {
private fb = inject(FormBuilder);
categories$!: Observable;
+ parentCategories$!: Observable;
categoryForm: FormGroup;
selectedCategoryId: string | null = null;
+
+ // --- NEUE EIGENSCHAFTEN FÜR BILD-MANAGEMENT ---
selectedFile: File | null = null;
+ existingImageUrl: string | null = null;
+ // --- ENDE NEU ---
constructor() {
this.categoryForm = this.fb.group({
@@ -26,6 +31,7 @@ export class CategoryListComponent implements OnInit {
slug: ['', Validators.required],
description: [''],
isActive: [true],
+ parentcategorieId: [null]
});
}
@@ -35,45 +41,74 @@ export class CategoryListComponent implements OnInit {
loadCategories(): void {
this.categories$ = this.categoryService.getAll();
+ this.updateParentCategoryList();
}
onFileChange(event: Event): void {
const element = event.currentTarget as HTMLInputElement;
- let fileList: FileList | null = element.files;
- if (fileList) {
+ const fileList: FileList | null = element.files;
+ if (fileList && fileList.length > 0) {
this.selectedFile = fileList[0];
+ // Zeige eine Vorschau des neu ausgewählten Bildes an
+ this.existingImageUrl = URL.createObjectURL(this.selectedFile);
}
}
selectCategory(category: Category): void {
this.selectedCategoryId = category.id;
this.categoryForm.patchValue(category);
+
+ // --- NEU: Bild-URL speichern ---
+ this.existingImageUrl = category.imageUrl || null;
+
+ this.updateParentCategoryList();
}
clearSelection(): void {
this.selectedCategoryId = null;
- this.categoryForm.reset({ isActive: true });
+ this.categoryForm.reset({ isActive: true, parentcategorieId: null });
+
+ // --- NEU: Bild-Referenzen zurücksetzen ---
this.selectedFile = null;
+ this.existingImageUrl = null;
+
+ this.updateParentCategoryList();
+ }
+
+ // --- NEU: Methode zum Entfernen des Bildes ---
+ removeImage(): void {
+ this.selectedFile = null;
+ this.existingImageUrl = null;
}
onSubmit(): void {
if (this.categoryForm.invalid) return;
const formData = new FormData();
- Object.keys(this.categoryForm.value).forEach(key => {
- formData.append(key, this.categoryForm.value[key]);
+ const formValue = this.categoryForm.value;
+
+ Object.keys(formValue).forEach(key => {
+ const value = formValue[key] === null || formValue[key] === undefined ? '' : formValue[key];
+ formData.append(key, value);
});
+ // --- ÜBERARBEITETE BILD-LOGIK ---
if (this.selectedFile) {
+ // Nur wenn eine NEUE Datei ausgewählt wurde, wird sie gesendet.
formData.append('ImageFile', this.selectedFile, this.selectedFile.name);
+ } else if (this.existingImageUrl) {
+ // Wenn keine neue Datei da ist, aber ein altes Bild existiert,
+ // senden wir die URL, damit das Backend weiß, dass es erhalten bleiben soll.
+ formData.append('ImageUrl', this.existingImageUrl);
}
+ // Wenn beides null ist (z.B. nach Klick auf "Bild entfernen"),
+ // wird kein Bild-Parameter gesendet und das Backend sollte das Bild löschen.
+ // --- ENDE ÜBERARBEITUNG ---
if (this.selectedCategoryId) {
- // Update
formData.append('Id', this.selectedCategoryId);
this.categoryService.update(this.selectedCategoryId, formData).subscribe(() => this.reset());
} else {
- // Create
this.categoryService.create(formData).subscribe(() => this.reset());
}
}
@@ -88,4 +123,10 @@ export class CategoryListComponent implements OnInit {
this.loadCategories();
this.clearSelection();
}
+
+ private updateParentCategoryList(): void {
+ this.parentCategories$ = this.categories$.pipe(
+ map(categories => categories.filter(c => c.id !== this.selectedCategoryId))
+ );
+ }
}
\ No newline at end of file
diff --git a/src/app/features/components/discounts/discount-list/discount-list.component.html b/src/app/features/components/discounts/discount-list/discount-list.component.html
index f8bb460..cea832c 100644
--- a/src/app/features/components/discounts/discount-list/discount-list.component.html
+++ b/src/app/features/components/discounts/discount-list/discount-list.component.html
@@ -3,28 +3,83 @@
+
\ No newline at end of file
diff --git a/src/app/features/components/discounts/discount-list/discount-list.component.ts b/src/app/features/components/discounts/discount-list/discount-list.component.ts
index 525d066..a49f0dd 100644
--- a/src/app/features/components/discounts/discount-list/discount-list.component.ts
+++ b/src/app/features/components/discounts/discount-list/discount-list.component.ts
@@ -1,11 +1,20 @@
import { Component, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
-import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
+import { FormBuilder, FormGroup, FormArray, ReactiveFormsModule, Validators } from '@angular/forms';
import { Observable } from 'rxjs';
+
+// Models
import { Discount } from '../../../../core/models/discount.model';
-import { DiscountService } from '../../../services/discount.service';
+import { AdminProduct } from '../../../../core/models/product.model';
+import { Category } from '../../../../core/models/category.model';
+
import { DiscountType } from '../../../../core/enums/shared.enum';
+// Services
+import { DiscountService } from '../../../services/discount.service';
+import { ProductService } from '../../../services/product.service';
+import { CategoryService } from '../../../services/category.service';
+
@Component({
selector: 'app-discount-list',
standalone: true,
@@ -13,10 +22,18 @@ import { DiscountType } from '../../../../core/enums/shared.enum';
templateUrl: './discount-list.component.html',
})
export class DiscountListComponent implements OnInit {
+ // --- Service Injection ---
private discountService = inject(DiscountService);
+ private productService = inject(ProductService);
+ private categoryService = inject(CategoryService);
private fb = inject(FormBuilder);
+ // --- Data Observables ---
discounts$!: Observable;
+ allProducts$!: Observable;
+ allCategories$!: Observable;
+
+ // --- Form Properties ---
discountForm: FormGroup;
selectedDiscountId: string | null = null;
discountTypes: DiscountType[] = ['Percentage', 'FixedAmount'];
@@ -29,31 +46,87 @@ export class DiscountListComponent implements OnInit {
couponCode: [''],
requiresCouponCode: [false],
isActive: [true],
- startDate: [new Date().toISOString().split('T')[0], Validators.required]
+ startDate: [new Date().toISOString().split('T')[0], Validators.required],
+ // +++ HIER SIND DIE FEHLENDEN FELDER +++
+ endDate: [null],
+ minimumOrderAmount: [null, [Validators.min(0)]],
+ maximumUsageCount: [null, [Validators.min(0)]],
+ description: [''],
+ assignedProductIds: this.fb.array([]),
+ assignedCategoryIds: this.fb.array([])
});
}
- ngOnInit(): void { this.loadDiscounts(); }
- loadDiscounts(): void { this.discounts$ = this.discountService.getAll(); }
+ get assignedProductIds(): FormArray {
+ return this.discountForm.get('assignedProductIds') as FormArray;
+ }
+
+ get assignedCategoryIds(): FormArray {
+ return this.discountForm.get('assignedCategoryIds') as FormArray;
+ }
+
+ ngOnInit(): void {
+ this.loadInitialData();
+ }
+
+ loadInitialData(): void {
+ this.discounts$ = this.discountService.getAll();
+ this.allProducts$ = this.productService.getAll();
+ this.allCategories$ = this.categoryService.getAll();
+ }
selectDiscount(discount: Discount): void {
this.selectedDiscountId = discount.id;
- // Format date for the input[type=date]
- const formattedDiscount = {
+ this.discountForm.patchValue({
...discount,
- startDate: new Date(discount.startDate).toISOString().split('T')[0]
- };
- this.discountForm.patchValue(formattedDiscount);
+ startDate: new Date(discount.startDate).toISOString().split('T')[0],
+ endDate: discount.endDate ? new Date(discount.endDate).toISOString().split('T')[0] : null,
+ });
+
+ this.assignedProductIds.clear();
+ discount.assignedProductIds?.forEach(id => this.assignedProductIds.push(this.fb.control(id)));
+
+ this.assignedCategoryIds.clear();
+ discount.assignedCategoryIds?.forEach(id => this.assignedCategoryIds.push(this.fb.control(id)));
}
clearSelection(): void {
this.selectedDiscountId = null;
- this.discountForm.reset({
- discountType: 'Percentage',
- isActive: true,
+ this.discountForm.reset({
+ name: '',
+ discountType: 'Percentage',
+ discountValue: 0,
+ couponCode: '',
requiresCouponCode: false,
- startDate: new Date().toISOString().split('T')[0]
+ isActive: true,
+ startDate: new Date().toISOString().split('T')[0],
+ endDate: null,
+ minimumOrderAmount: null,
+ maximumUsageCount: null,
+ description: '',
});
+ this.assignedProductIds.clear();
+ this.assignedCategoryIds.clear();
+ }
+
+ addProduct(productId: string | null): void {
+ if (productId && !this.assignedProductIds.value.includes(productId)) {
+ this.assignedProductIds.push(this.fb.control(productId));
+ }
+ }
+
+ removeProduct(index: number): void {
+ this.assignedProductIds.removeAt(index);
+ }
+
+ addCategory(categoryId: string | null): void {
+ if (categoryId && !this.assignedCategoryIds.value.includes(categoryId)) {
+ this.assignedCategoryIds.push(this.fb.control(categoryId));
+ }
+ }
+
+ removeCategory(index: number): void {
+ this.assignedCategoryIds.removeAt(index);
}
onSubmit(): void {
@@ -62,8 +135,12 @@ export class DiscountListComponent implements OnInit {
const formValue = this.discountForm.value;
const dataToSend: Discount = {
...formValue,
- id: this.selectedDiscountId || '00000000-0000-0000-0000-000000000000', // Dummy ID for create
- startDate: new Date(formValue.startDate).toISOString()
+ id: this.selectedDiscountId || undefined,
+ startDate: new Date(formValue.startDate).toISOString(),
+ endDate: formValue.endDate ? new Date(formValue.endDate).toISOString() : null,
+ // Die Werte aus den FormArrays sind bereits korrekte Arrays von Strings
+ assignedProductIds: this.assignedProductIds.value,
+ assignedCategoryIds: this.assignedCategoryIds.value
};
if (this.selectedDiscountId) {
@@ -75,12 +152,20 @@ export class DiscountListComponent implements OnInit {
onDelete(id: string): void {
if (confirm('Rabatt wirklich löschen?')) {
- this.discountService.delete(id).subscribe(() => this.loadDiscounts());
+ this.discountService.delete(id).subscribe(() => this.loadInitialData());
}
}
private reset(): void {
- this.loadDiscounts();
+ this.loadInitialData();
this.clearSelection();
}
+
+ getProductName(productId: string, products: AdminProduct[] | null): string {
+ return products?.find(p => p.id === productId)?.name || 'Unbekanntes Produkt';
+ }
+
+ getCategoryName(categoryId: string, categories: Category[] | null): string {
+ return categories?.find(c => c.id === categoryId)?.name || 'Unbekannte Kategorie';
+ }
}
\ No newline at end of file
diff --git a/src/app/features/components/discounts/discounts.routes.ts b/src/app/features/components/discounts/discounts.routes.ts
new file mode 100644
index 0000000..e45ebb0
--- /dev/null
+++ b/src/app/features/components/discounts/discounts.routes.ts
@@ -0,0 +1,10 @@
+import { Routes } from '@angular/router';
+import { DiscountListComponent } from './discount-list/discount-list.component';
+
+export const DISCOUNTS_ROUTES: Routes = [
+ {
+ path: '',
+ component: DiscountListComponent,
+ title: '',
+ },
+];
diff --git a/src/app/features/components/orders/orders.routes.ts b/src/app/features/components/orders/orders.routes.ts
new file mode 100644
index 0000000..d71b89c
--- /dev/null
+++ b/src/app/features/components/orders/orders.routes.ts
@@ -0,0 +1,10 @@
+import { Routes } from '@angular/router';
+import { OrderListComponent } from './order-list/order-list.component';
+
+export const ORDERS_ROUTES: Routes = [
+ {
+ path: '',
+ component: OrderListComponent,
+ title: '',
+ },
+];
diff --git a/src/app/features/services/analytics.service.ts b/src/app/features/services/analytics.service.ts
index 895c0f1..8465fa2 100644
--- a/src/app/features/services/analytics.service.ts
+++ b/src/app/features/services/analytics.service.ts
@@ -9,7 +9,7 @@ import { AnalyticsPeriod } from '../../core/enums/shared.enum';
export class AnalyticsService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminAnalytics';
+ private readonly endpoint = '/admin/AdminAnalytics';
get(period: AnalyticsPeriod): Observable {
const params = new HttpParams().set('period', period);
diff --git a/src/app/features/services/category.service.ts b/src/app/features/services/category.service.ts
index d248e6b..2194830 100644
--- a/src/app/features/services/category.service.ts
+++ b/src/app/features/services/category.service.ts
@@ -8,7 +8,7 @@ import { Category } from '../../core/models/category.model';
export class CategoryService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminCategories';
+ private readonly endpoint = '/admin/AdminCategories';
getAll(): Observable {
return this.http.get(`${this.apiUrl}${this.endpoint}`);
@@ -29,4 +29,4 @@ export class CategoryService {
delete(id: string): Observable {
return this.http.delete(`${this.apiUrl}${this.endpoint}/${id}`);
}
-}
\ No newline at end of file
+}
diff --git a/src/app/features/services/discount.service.ts b/src/app/features/services/discount.service.ts
index 553d1ca..d21de73 100644
--- a/src/app/features/services/discount.service.ts
+++ b/src/app/features/services/discount.service.ts
@@ -8,7 +8,7 @@ import { Discount } from '../../core/models/discount.model';
export class DiscountService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminDiscounts';
+ private readonly endpoint = '/admin/AdminDiscounts';
getAll(): Observable {
return this.http.get(`${this.apiUrl}${this.endpoint}`);
diff --git a/src/app/features/services/order.service.ts b/src/app/features/services/order.service.ts
index 91515b0..32acf8b 100644
--- a/src/app/features/services/order.service.ts
+++ b/src/app/features/services/order.service.ts
@@ -8,7 +8,7 @@ import { OrderDetail, OrderSummary, UpdateOrderStatusRequest } from '../../core/
export class OrderService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminOrders';
+ private readonly endpoint = '/admin/AdminOrders';
getAll(): Observable {
return this.http.get(`${this.apiUrl}${this.endpoint}`);
diff --git a/src/app/features/services/payment-method.service.ts b/src/app/features/services/payment-method.service.ts
index 5441c9c..6b87779 100644
--- a/src/app/features/services/payment-method.service.ts
+++ b/src/app/features/services/payment-method.service.ts
@@ -8,7 +8,7 @@ import { AdminPaymentMethod } from '../../core/models/payment.model';
export class PaymentMethodService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminPaymentMethods';
+ private readonly endpoint = '/admin/AdminPaymentMethods';
getAll(): Observable {
return this.http.get(`${this.apiUrl}${this.endpoint}`);
diff --git a/src/app/features/services/product.service.ts b/src/app/features/services/product.service.ts
index 7332a4e..c6e7bae 100644
--- a/src/app/features/services/product.service.ts
+++ b/src/app/features/services/product.service.ts
@@ -8,7 +8,7 @@ import { AdminProduct } from '../../core/models/product.model';
export class ProductService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminProducts';
+ private readonly endpoint = '/admin/AdminProducts';
getAll(): Observable {
return this.http.get(`${this.apiUrl}${this.endpoint}`);
diff --git a/src/app/features/services/review.service.ts b/src/app/features/services/review.service.ts
index 3860b19..cbb5dd2 100644
--- a/src/app/features/services/review.service.ts
+++ b/src/app/features/services/review.service.ts
@@ -8,7 +8,7 @@ import { Review } from '../../core/models/review.model';
export class ReviewService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminReviews';
+ private readonly endpoint = '/admin/AdminReviews';
getAll(): Observable {
return this.http.get(`${this.apiUrl}${this.endpoint}`);
diff --git a/src/app/features/services/setting.service.ts b/src/app/features/services/setting.service.ts
index 702f2a7..139be92 100644
--- a/src/app/features/services/setting.service.ts
+++ b/src/app/features/services/setting.service.ts
@@ -8,7 +8,7 @@ import { Setting } from '../../core/models/setting.model';
export class SettingService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminSettings';
+ private readonly endpoint = '/admin/AdminSettings';
getAllGrouped(): Observable<{ [group: string]: Setting[] }> {
return this.http.get<{ [group: string]: Setting[] }>(`${this.apiUrl}${this.endpoint}`);
diff --git a/src/app/features/services/shipping-method.service.ts b/src/app/features/services/shipping-method.service.ts
index 1c84c62..fc38224 100644
--- a/src/app/features/services/shipping-method.service.ts
+++ b/src/app/features/services/shipping-method.service.ts
@@ -8,7 +8,7 @@ import { ShippingMethod } from '../../core/models/shipping.model';
export class ShippingMethodService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminShippingMethods';
+ private readonly endpoint = '/admin/AdminShippingMethods';
getAll(): Observable {
return this.http.get(`${this.apiUrl}${this.endpoint}`);
diff --git a/src/app/features/services/shop-info.service.ts b/src/app/features/services/shop-info.service.ts
index e4b305d..2407b18 100644
--- a/src/app/features/services/shop-info.service.ts
+++ b/src/app/features/services/shop-info.service.ts
@@ -8,7 +8,7 @@ import { AdminShopInfo } from '../../core/models/shop.model';
export class ShopInfoService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminShopInfo';
+ private readonly endpoint = '/admin/AdminShopInfo';
get(): Observable {
return this.http.get(`${this.apiUrl}${this.endpoint}`);
diff --git a/src/app/features/services/supplier.service.ts b/src/app/features/services/supplier.service.ts
index 40ed6bd..8bd462a 100644
--- a/src/app/features/services/supplier.service.ts
+++ b/src/app/features/services/supplier.service.ts
@@ -8,7 +8,7 @@ import { Supplier } from '../../core/models/supplier.model';
export class SupplierService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminSuppliers';
+ private readonly endpoint = '/admin/AdminSuppliers';
getAll(): Observable {
return this.http.get(`${this.apiUrl}${this.endpoint}`);
diff --git a/src/app/features/services/user.service.ts b/src/app/features/services/user.service.ts
index fa00714..86284d5 100644
--- a/src/app/features/services/user.service.ts
+++ b/src/app/features/services/user.service.ts
@@ -8,7 +8,7 @@ import { User, UpdateUserRolesRequest } from '../../core/models/user.model';
export class UserService {
private http = inject(HttpClient);
private apiUrl = inject(API_URL);
- private readonly endpoint = '/AdminUsers';
+ private readonly endpoint = '/admin/AdminUsers';
getAll(): Observable {
return this.http.get(`${this.apiUrl}${this.endpoint}`);