components
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
import { KpiColor } from "../types/dashboard";
|
// import { KpiColor } from "../types/dashboard";
|
||||||
|
|
||||||
export interface Kpi {
|
export interface Kpi {
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
color: KpiColor; // <-- Hier verwenden wir den importierten Typ
|
color: any; // <-- Hier verwenden wir den importierten Typ
|
||||||
iconName: string;
|
iconName: string;
|
||||||
}
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type KpiColor = 'blue' | 'green' | 'orange' | 'purple';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type OrderStatus = 'completed' | 'processing' | 'cancelled' | 'info';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type PillStatus = 'success' | 'warning' | 'danger' | 'info';
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Kategorien verwalten</h1>
|
||||||
|
|
||||||
|
<!-- Formular für Erstellen/Bearbeiten -->
|
||||||
|
<form [formGroup]="categoryForm" (ngSubmit)="onSubmit()">
|
||||||
|
<h3>{{ selectedCategoryId ? 'Kategorie bearbeiten' : 'Neue Kategorie erstellen' }}</h3>
|
||||||
|
<input type="text" formControlName="name" placeholder="Name">
|
||||||
|
<input type="text" formControlName="slug" placeholder="Slug">
|
||||||
|
<textarea formControlName="description" placeholder="Beschreibung"></textarea>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" formControlName="isActive"> Aktiv
|
||||||
|
</label>
|
||||||
|
<input type="file" (change)="onFileChange($event)">
|
||||||
|
<button type="submit" [disabled]="categoryForm.invalid">{{ selectedCategoryId ? 'Aktualisieren' : 'Erstellen' }}</button>
|
||||||
|
<button type="button" *ngIf="selectedCategoryId" (click)="clearSelection()">Abbrechen</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<!-- Liste der Kategorien -->
|
||||||
|
<h2>Bestehende Kategorien</h2>
|
||||||
|
<ul>
|
||||||
|
<li *ngFor="let category of categories$ | async">
|
||||||
|
{{ category.name }} (Slug: {{ category.slug }}) - Aktiv: {{ category.isActive }}
|
||||||
|
<button (click)="selectCategory(category)">Bearbeiten</button>
|
||||||
|
<button (click)="onDelete(category.id)">Löschen</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
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 { Category } from '../../../../core/models/category.model';
|
||||||
|
import { CategoryService } from '../../../services/category.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-category-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, ReactiveFormsModule],
|
||||||
|
templateUrl: './category-list.component.html',
|
||||||
|
})
|
||||||
|
export class CategoryListComponent implements OnInit {
|
||||||
|
private categoryService = inject(CategoryService);
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
|
categories$!: Observable<Category[]>;
|
||||||
|
categoryForm: FormGroup;
|
||||||
|
selectedCategoryId: string | null = null;
|
||||||
|
selectedFile: File | null = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.categoryForm = this.fb.group({
|
||||||
|
name: ['', Validators.required],
|
||||||
|
slug: ['', Validators.required],
|
||||||
|
description: [''],
|
||||||
|
isActive: [true],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadCategories();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadCategories(): void {
|
||||||
|
this.categories$ = this.categoryService.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
onFileChange(event: Event): void {
|
||||||
|
const element = event.currentTarget as HTMLInputElement;
|
||||||
|
let fileList: FileList | null = element.files;
|
||||||
|
if (fileList) {
|
||||||
|
this.selectedFile = fileList[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectCategory(category: Category): void {
|
||||||
|
this.selectedCategoryId = category.id;
|
||||||
|
this.categoryForm.patchValue(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelection(): void {
|
||||||
|
this.selectedCategoryId = null;
|
||||||
|
this.categoryForm.reset({ isActive: true });
|
||||||
|
this.selectedFile = 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]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.selectedFile) {
|
||||||
|
formData.append('ImageFile', this.selectedFile, this.selectedFile.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDelete(id: string): void {
|
||||||
|
if (confirm('Möchten Sie diese Kategorie wirklich löschen?')) {
|
||||||
|
this.categoryService.delete(id).subscribe(() => this.loadCategories());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private reset(): void {
|
||||||
|
this.loadCategories();
|
||||||
|
this.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Admin Dashboard</h1>
|
||||||
|
<div>
|
||||||
|
<button (click)="loadAnalytics('Last7Days')">Letzte 7 Tage</button>
|
||||||
|
<button (click)="loadAnalytics('Last30Days')">Letzte 30 Tage</button>
|
||||||
|
<button (click)="loadAnalytics('AllTime')">Gesamt</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="analytics$ | async as data">
|
||||||
|
<h2>KPIs</h2>
|
||||||
|
<pre>{{ data.kpiSummary | json }}</pre>
|
||||||
|
|
||||||
|
<h2>Verkäufe</h2>
|
||||||
|
<pre>{{ data.salesOverTime | json }}</pre>
|
||||||
|
|
||||||
|
<h2>Top Produkte</h2>
|
||||||
|
<pre>{{ data.topPerformingProducts | json }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Component, OnInit, inject } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { Analytics } from '../../../../core/models/analytics.model';
|
||||||
|
import { AnalyticsService } from '../../../services/analytics.service';
|
||||||
|
import { AnalyticsPeriod } from '../../../../core/enums/shared.enum';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-admin-dashboard',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule],
|
||||||
|
templateUrl: './dashboard.component.html',
|
||||||
|
})
|
||||||
|
export class AdminDashboardComponent implements OnInit {
|
||||||
|
private analyticsService = inject(AnalyticsService);
|
||||||
|
analytics$!: Observable<Analytics>;
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadAnalytics('Last30Days');
|
||||||
|
}
|
||||||
|
|
||||||
|
loadAnalytics(period: AnalyticsPeriod): void {
|
||||||
|
this.analytics$ = this.analyticsService.get(period);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { IconComponent } from '../../../../shared/components/ui/icon/icon.component';
|
import { IconComponent } from '../../../../shared/components/ui/icon/icon.component';
|
||||||
import { CardComponent } from '../../../../shared/components/ui/card/card.component';
|
import { CardComponent } from '../../../../shared/components/ui/card/card.component';
|
||||||
|
|
||||||
import { KpiColor } from '../../../../core/types/dashboard';
|
// import { KpiColor } from '../../../../core/types/dashboard';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-kpi-card',
|
selector: 'app-kpi-card',
|
||||||
@@ -15,7 +15,7 @@ import { KpiColor } from '../../../../core/types/dashboard';
|
|||||||
export class KpiCardComponent {
|
export class KpiCardComponent {
|
||||||
@Input() value: string = '';
|
@Input() value: string = '';
|
||||||
@Input() label: string = '';
|
@Input() label: string = '';
|
||||||
@Input() color: KpiColor = 'blue';
|
@Input() color: any = 'blue';
|
||||||
@Input() iconName: string | null = null;
|
@Input() iconName: string | null = null;
|
||||||
@Input() svgColor: string | null = null;
|
@Input() svgColor: string | null = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Rabatte verwalten</h1>
|
||||||
|
|
||||||
|
<form [formGroup]="discountForm" (ngSubmit)="onSubmit()">
|
||||||
|
<h3>{{ selectedDiscountId ? "Rabatt bearbeiten" : "Neuer Rabatt" }}</h3>
|
||||||
|
<input type="text" formControlName="name" placeholder="Name des Rabatts" />
|
||||||
|
<select formControlName="discountType">
|
||||||
|
<option *ngFor="let type of discountTypes" [value]="type">
|
||||||
|
{{ type }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
formControlName="discountValue"
|
||||||
|
placeholder="Wert (z.B. 10 für 10% oder 10€)"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
formControlName="couponCode"
|
||||||
|
placeholder="Gutscheincode (optional)"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
><input type="checkbox" formControlName="requiresCouponCode" /> Code
|
||||||
|
erforderlich</label
|
||||||
|
>
|
||||||
|
<label><input type="checkbox" formControlName="isActive" /> Aktiv</label>
|
||||||
|
<input type="date" formControlName="startDate" />
|
||||||
|
<button type="submit" [disabled]="discountForm.invalid">
|
||||||
|
{{ selectedDiscountId ? "Aktualisieren" : "Erstellen" }}
|
||||||
|
</button>
|
||||||
|
<button type="button" *ngIf="selectedDiscountId" (click)="clearSelection()">
|
||||||
|
Abbrechen
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<h2>Bestehende Rabatte</h2>
|
||||||
|
<ul>
|
||||||
|
<li *ngFor="let discount of discounts$ | async">
|
||||||
|
{{ discount.name }} ({{ discount.discountValue
|
||||||
|
}}{{ discount.discountType === "Percentage" ? "%" : "€" }})
|
||||||
|
<button (click)="selectDiscount(discount)">Bearbeiten</button>
|
||||||
|
<button (click)="onDelete(discount.id)">Löschen</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
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 { Discount } from '../../../../core/models/discount.model';
|
||||||
|
import { DiscountService } from '../../../services/discount.service';
|
||||||
|
import { DiscountType } from '../../../../core/enums/shared.enum';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-discount-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, ReactiveFormsModule],
|
||||||
|
templateUrl: './discount-list.component.html',
|
||||||
|
})
|
||||||
|
export class DiscountListComponent implements OnInit {
|
||||||
|
private discountService = inject(DiscountService);
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
|
discounts$!: Observable<Discount[]>;
|
||||||
|
discountForm: FormGroup;
|
||||||
|
selectedDiscountId: string | null = null;
|
||||||
|
discountTypes: DiscountType[] = ['Percentage', 'FixedAmount'];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.discountForm = this.fb.group({
|
||||||
|
name: ['', Validators.required],
|
||||||
|
discountType: ['Percentage', Validators.required],
|
||||||
|
discountValue: [0, [Validators.required, Validators.min(0)]],
|
||||||
|
couponCode: [''],
|
||||||
|
requiresCouponCode: [false],
|
||||||
|
isActive: [true],
|
||||||
|
startDate: [new Date().toISOString().split('T')[0], Validators.required]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void { this.loadDiscounts(); }
|
||||||
|
loadDiscounts(): void { this.discounts$ = this.discountService.getAll(); }
|
||||||
|
|
||||||
|
selectDiscount(discount: Discount): void {
|
||||||
|
this.selectedDiscountId = discount.id;
|
||||||
|
// Format date for the input[type=date]
|
||||||
|
const formattedDiscount = {
|
||||||
|
...discount,
|
||||||
|
startDate: new Date(discount.startDate).toISOString().split('T')[0]
|
||||||
|
};
|
||||||
|
this.discountForm.patchValue(formattedDiscount);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelection(): void {
|
||||||
|
this.selectedDiscountId = null;
|
||||||
|
this.discountForm.reset({
|
||||||
|
discountType: 'Percentage',
|
||||||
|
isActive: true,
|
||||||
|
requiresCouponCode: false,
|
||||||
|
startDate: new Date().toISOString().split('T')[0]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.discountForm.invalid) return;
|
||||||
|
|
||||||
|
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()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.selectedDiscountId) {
|
||||||
|
this.discountService.update(this.selectedDiscountId, dataToSend).subscribe(() => this.reset());
|
||||||
|
} else {
|
||||||
|
this.discountService.create(dataToSend).subscribe(() => this.reset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDelete(id: string): void {
|
||||||
|
if (confirm('Rabatt wirklich löschen?')) {
|
||||||
|
this.discountService.delete(id).subscribe(() => this.loadDiscounts());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private reset(): void {
|
||||||
|
this.loadDiscounts();
|
||||||
|
this.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Bestellungen verwalten</h1>
|
||||||
|
|
||||||
|
<!-- Liste -->
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Bestellnr.</th>
|
||||||
|
<th>Datum</th>
|
||||||
|
<th>Kunde</th>
|
||||||
|
<th>Betrag</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Aktionen</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let order of orders$ | async">
|
||||||
|
<td>{{ order.orderNumber }}</td>
|
||||||
|
<td>{{ order.orderDate | date : "short" }}</td>
|
||||||
|
<td>{{ order.customerName }}</td>
|
||||||
|
<td>{{ order.totalAmount | currency : "EUR" }}</td>
|
||||||
|
<td>
|
||||||
|
<select (change)="updateStatus(order.id, $event)">
|
||||||
|
<option
|
||||||
|
*ngFor="let status of orderStatuses"
|
||||||
|
[value]="status"
|
||||||
|
[selected]="status === order.status"
|
||||||
|
>
|
||||||
|
{{ status }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td><button (click)="viewDetails(order.id)">Details</button></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<!-- Detailansicht -->
|
||||||
|
<div *ngIf="selectedOrder">
|
||||||
|
<h2>Details für Bestellung {{ selectedOrder.orderNumber }}</h2>
|
||||||
|
<pre>{{ selectedOrder | json }}</pre>
|
||||||
|
<button (click)="selectedOrder = null">Schließen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { Component, OnInit, inject } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { OrderDetail, OrderSummary } from '../../../../core/models/order.model';
|
||||||
|
import { OrderService } from '../../../services/order.service';
|
||||||
|
import { OrderStatus } from '../../../../core/enums/shared.enum';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-order-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule],
|
||||||
|
templateUrl: './order-list.component.html',
|
||||||
|
})
|
||||||
|
export class OrderListComponent implements OnInit {
|
||||||
|
private orderService = inject(OrderService);
|
||||||
|
|
||||||
|
orders$!: Observable<OrderSummary[]>;
|
||||||
|
selectedOrder: OrderDetail | null = null;
|
||||||
|
orderStatuses: OrderStatus[] = [
|
||||||
|
'Pending',
|
||||||
|
'Processing',
|
||||||
|
'Shipped',
|
||||||
|
'Delivered',
|
||||||
|
'Cancelled',
|
||||||
|
'Refunded',
|
||||||
|
];
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadOrders();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadOrders(): void {
|
||||||
|
this.orders$ = this.orderService.getAll();
|
||||||
|
this.selectedOrder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
viewDetails(id: string): void {
|
||||||
|
this.orderService.getById(id).subscribe((details) => {
|
||||||
|
this.selectedOrder = details;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStatus(id: string, event: Event): void {
|
||||||
|
const newStatus = (event.target as HTMLSelectElement).value as OrderStatus;
|
||||||
|
this.orderService.updateStatus(id, { newStatus }).subscribe(() => {
|
||||||
|
this.loadOrders(); // Lade alles neu, um die Änderungen zu sehen
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Zahlungsmethoden verwalten</h1>
|
||||||
|
<form [formGroup]="methodForm" (ngSubmit)="onSubmit()">
|
||||||
|
<h3>{{ selectedMethodId ? 'Methode bearbeiten' : 'Neue Methode' }}</h3>
|
||||||
|
<input type="text" formControlName="name" placeholder="Name">
|
||||||
|
<textarea formControlName="description" placeholder="Beschreibung"></textarea>
|
||||||
|
<select formControlName="paymentGatewayType">
|
||||||
|
<option *ngFor="let type of gatewayTypes" [value]="type">{{ type }}</option>
|
||||||
|
</select>
|
||||||
|
<label><input type="checkbox" formControlName="isActive"> Aktiv</label>
|
||||||
|
<button type="submit" [disabled]="methodForm.invalid">{{ selectedMethodId ? 'Aktualisieren' : 'Erstellen' }}</button>
|
||||||
|
<button type="button" *ngIf="selectedMethodId" (click)="clearSelection()">Abbrechen</button>
|
||||||
|
</form>
|
||||||
|
<hr>
|
||||||
|
<h2>Bestehende Methoden</h2>
|
||||||
|
<ul>
|
||||||
|
<li *ngFor="let method of methods$ | async">
|
||||||
|
{{ method.name }} (Typ: {{ method.paymentGatewayType }}) - Aktiv: {{ method.isActive }}
|
||||||
|
<button (click)="selectMethod(method)">Bearbeiten</button>
|
||||||
|
<button (click)="onDelete(method.id)">Löschen</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
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 { AdminPaymentMethod } from '../../../../core/models/payment.model';
|
||||||
|
import { PaymentGatewayType } from '../../../../core/enums/shared.enum';
|
||||||
|
import { PaymentMethodService } from '../../../services/payment-method.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-payment-method-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, ReactiveFormsModule],
|
||||||
|
templateUrl: './payment-method-list.component.html',
|
||||||
|
})
|
||||||
|
export class PaymentMethodListComponent implements OnInit {
|
||||||
|
private paymentMethodService = inject(PaymentMethodService);
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
|
methods$!: Observable<AdminPaymentMethod[]>;
|
||||||
|
methodForm: FormGroup;
|
||||||
|
selectedMethodId: string | null = null;
|
||||||
|
gatewayTypes: PaymentGatewayType[] = ['BankTransfer', 'Invoice', 'PayPal', 'Stripe', 'CashOnDelivery'];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.methodForm = this.fb.group({
|
||||||
|
name: ['', Validators.required],
|
||||||
|
description: [''],
|
||||||
|
isActive: [true],
|
||||||
|
paymentGatewayType: ['Invoice', Validators.required]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void { this.loadMethods(); }
|
||||||
|
loadMethods(): void { this.methods$ = this.paymentMethodService.getAll(); }
|
||||||
|
|
||||||
|
selectMethod(method: AdminPaymentMethod): void {
|
||||||
|
this.selectedMethodId = method.id;
|
||||||
|
this.methodForm.patchValue(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelection(): void {
|
||||||
|
this.selectedMethodId = null;
|
||||||
|
this.methodForm.reset({ isActive: true, paymentGatewayType: 'Invoice' });
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.methodForm.invalid) return;
|
||||||
|
const dataToSend = { ...this.methodForm.value, id: this.selectedMethodId || '0' };
|
||||||
|
|
||||||
|
if (this.selectedMethodId) {
|
||||||
|
this.paymentMethodService.update(this.selectedMethodId, dataToSend).subscribe(() => this.reset());
|
||||||
|
} else {
|
||||||
|
this.paymentMethodService.create(dataToSend).subscribe(() => this.reset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDelete(id: string): void {
|
||||||
|
if (confirm('Zahlungsmethode wirklich löschen?')) {
|
||||||
|
this.paymentMethodService.delete(id).subscribe(() => this.loadMethods());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private reset(): void {
|
||||||
|
this.loadMethods();
|
||||||
|
this.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Produkte verwalten</h1>
|
||||||
|
|
||||||
|
<!-- Formular -->
|
||||||
|
<form [formGroup]="productForm" (ngSubmit)="onSubmit()">
|
||||||
|
<h3>{{ selectedProductId ? 'Produkt bearbeiten' : 'Neues Produkt' }}</h3>
|
||||||
|
<input type="text" formControlName="name" placeholder="Produktname">
|
||||||
|
<input type="text" formControlName="slug" placeholder="Slug">
|
||||||
|
<input type="text" formControlName="sku" placeholder="SKU">
|
||||||
|
<input type="number" formControlName="price" placeholder="Preis">
|
||||||
|
<input type="number" formControlName="stockQuantity" placeholder="Lagerbestand">
|
||||||
|
<label><input type="checkbox" formControlName="isActive"> Aktiv</label>
|
||||||
|
<label><input type="checkbox" formControlName="isFeatured"> Hervorgehoben</label>
|
||||||
|
<button type="submit" [disabled]="productForm.invalid">{{ selectedProductId ? 'Aktualisieren' : 'Erstellen' }}</button>
|
||||||
|
<button type="button" *ngIf="selectedProductId" (click)="clearSelection()">Abbrechen</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<!-- Liste -->
|
||||||
|
<h2>Bestehende Produkte</h2>
|
||||||
|
<ul>
|
||||||
|
<li *ngFor="let product of products$ | async">
|
||||||
|
{{ product.name }} (SKU: {{ product.sku }}) - Preis: {{ product.price | number:'1.2-2' }} €
|
||||||
|
<button (click)="selectProduct(product)">Bearbeiten</button>
|
||||||
|
<button (click)="onDelete(product.id)">Löschen</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
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 { AdminProduct } from '../../../../core/models/product.model';
|
||||||
|
import { ProductService } from '../../../services/product.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-product-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, ReactiveFormsModule],
|
||||||
|
templateUrl: './product-list.component.html',
|
||||||
|
})
|
||||||
|
export class ProductListComponent implements OnInit {
|
||||||
|
private productService = inject(ProductService);
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
|
products$!: Observable<AdminProduct[]>;
|
||||||
|
productForm: FormGroup;
|
||||||
|
selectedProductId: string | null = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.productForm = this.fb.group({
|
||||||
|
name: ['', Validators.required],
|
||||||
|
slug: ['', Validators.required],
|
||||||
|
sku: ['', Validators.required],
|
||||||
|
description: [''],
|
||||||
|
price: [0, [Validators.required, Validators.min(0)]],
|
||||||
|
stockQuantity: [0, [Validators.required, Validators.min(0)]],
|
||||||
|
isActive: [true],
|
||||||
|
isFeatured: [false]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void { this.loadProducts(); }
|
||||||
|
loadProducts(): void { this.products$ = this.productService.getAll(); }
|
||||||
|
|
||||||
|
selectProduct(product: AdminProduct): void {
|
||||||
|
this.selectedProductId = product.id;
|
||||||
|
this.productForm.patchValue(product);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelection(): void {
|
||||||
|
this.selectedProductId = null;
|
||||||
|
this.productForm.reset({ isActive: true, isFeatured: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.productForm.invalid) return;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
Object.keys(this.productForm.value).forEach(key => {
|
||||||
|
formData.append(key, this.productForm.value[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.selectedProductId) {
|
||||||
|
formData.append('Id', this.selectedProductId);
|
||||||
|
this.productService.update(this.selectedProductId, formData).subscribe(() => this.reset());
|
||||||
|
} else {
|
||||||
|
this.productService.create(formData).subscribe(() => this.reset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDelete(id: string): void {
|
||||||
|
if (confirm('Produkt wirklich löschen?')) {
|
||||||
|
this.productService.delete(id).subscribe(() => this.loadProducts());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private reset(): void {
|
||||||
|
this.loadProducts();
|
||||||
|
this.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Bewertungen verwalten</h1>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Kunde</th>
|
||||||
|
<th>Produkt</th>
|
||||||
|
<th>Bewertung</th>
|
||||||
|
<th>Titel</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Aktionen</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let review of reviews$ | async">
|
||||||
|
<td>{{ review.customerName }}</td>
|
||||||
|
<td>{{ review.productName }}</td>
|
||||||
|
<td>{{ review.rating }}/5</td>
|
||||||
|
<td>{{ review.title }}</td>
|
||||||
|
<td>{{ review.isApproved ? "Freigegeben" : "Ausstehend" }}</td>
|
||||||
|
<td>
|
||||||
|
<button *ngIf="!review.isApproved" (click)="onApprove(review.id)">
|
||||||
|
Freigeben
|
||||||
|
</button>
|
||||||
|
<button (click)="onDelete(review.id)">Löschen</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { Component, OnInit, inject } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { Review } from '../../../../core/models/review.model';
|
||||||
|
import { ReviewService } from '../../../services/review.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-review-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule],
|
||||||
|
templateUrl: './review-list.component.html',
|
||||||
|
})
|
||||||
|
export class ReviewListComponent implements OnInit {
|
||||||
|
private reviewService = inject(ReviewService);
|
||||||
|
reviews$!: Observable<Review[]>;
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadReviews();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadReviews(): void {
|
||||||
|
this.reviews$ = this.reviewService.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
onApprove(id: string): void {
|
||||||
|
this.reviewService.approve(id).subscribe(() => this.loadReviews());
|
||||||
|
}
|
||||||
|
|
||||||
|
onDelete(id: string): void {
|
||||||
|
if (confirm('Bewertung wirklich löschen?')) {
|
||||||
|
this.reviewService.delete(id).subscribe(() => this.loadReviews());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Einstellungen verwalten</h1>
|
||||||
|
<form [formGroup]="settingsForm" (ngSubmit)="onSubmit()">
|
||||||
|
<div formArrayName="settings">
|
||||||
|
<div *ngFor="let group of settingGroups">
|
||||||
|
<h3>{{ group.groupName }}</h3>
|
||||||
|
<div *ngFor="let setting of group.settings; let i = index">
|
||||||
|
<!-- Find the correct form group in the FormArray by key -->
|
||||||
|
<ng-container
|
||||||
|
*ngFor="let control of settingsArray.controls; let j = index"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
*ngIf="control.get('key')?.value === setting.key"
|
||||||
|
[formGroupName]="j"
|
||||||
|
>
|
||||||
|
<label>{{ setting.description || setting.key }}</label>
|
||||||
|
<input type="text" formControlName="value" />
|
||||||
|
<label
|
||||||
|
><input type="checkbox" formControlName="isActive" />
|
||||||
|
Aktiv</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Einstellungen speichern</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { Component, OnInit, inject } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormBuilder, FormGroup, FormArray, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { Setting } from '../../../../core/models/setting.model';
|
||||||
|
import { SettingService } from '../../../services/setting.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-settings',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, ReactiveFormsModule],
|
||||||
|
templateUrl: './settings.component.html',
|
||||||
|
})
|
||||||
|
export class SettingsComponent implements OnInit {
|
||||||
|
private settingService = inject(SettingService);
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
|
settingsForm: FormGroup;
|
||||||
|
settingGroups: { groupName: string, settings: Setting[] }[] = [];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.settingsForm = this.fb.group({
|
||||||
|
settings: this.fb.array([])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get settingsArray(): FormArray {
|
||||||
|
return this.settingsForm.get('settings') as FormArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.settingService.getAllGrouped().subscribe(groupedSettings => {
|
||||||
|
this.settingsArray.clear();
|
||||||
|
this.settingGroups = [];
|
||||||
|
Object.keys(groupedSettings).forEach(groupName => {
|
||||||
|
const settings = groupedSettings[groupName];
|
||||||
|
this.settingGroups.push({ groupName, settings });
|
||||||
|
settings.forEach(setting => {
|
||||||
|
this.settingsArray.push(this.fb.group({
|
||||||
|
key: [setting.key],
|
||||||
|
value: [setting.value],
|
||||||
|
isActive: [setting.isActive]
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.settingsForm.invalid) return;
|
||||||
|
this.settingService.update(this.settingsForm.value.settings).subscribe(() => {
|
||||||
|
alert('Einstellungen gespeichert!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Versandmethoden verwalten</h1>
|
||||||
|
<form [formGroup]="methodForm" (ngSubmit)="onSubmit()">
|
||||||
|
<h3>{{ selectedMethodId ? 'Methode bearbeiten' : 'Neue Methode' }}</h3>
|
||||||
|
<input type="text" formControlName="name" placeholder="Name">
|
||||||
|
<textarea formControlName="description" placeholder="Beschreibung"></textarea>
|
||||||
|
<input type="number" formControlName="cost" placeholder="Kosten">
|
||||||
|
<label><input type="checkbox" formControlName="isActive"> Aktiv</label>
|
||||||
|
<button type="submit" [disabled]="methodForm.invalid">{{ selectedMethodId ? 'Aktualisieren' : 'Erstellen' }}</button>
|
||||||
|
<button type="button" *ngIf="selectedMethodId" (click)="clearSelection()">Abbrechen</button>
|
||||||
|
</form>
|
||||||
|
<hr>
|
||||||
|
<h2>Bestehende Methoden</h2>
|
||||||
|
<ul>
|
||||||
|
<li *ngFor="let method of methods$ | async">
|
||||||
|
{{ method.name }} ({{ method.cost | currency:'EUR' }}) - Aktiv: {{ method.isActive }}
|
||||||
|
<button (click)="selectMethod(method)">Bearbeiten</button>
|
||||||
|
<button (click)="onDelete(method.id)">Löschen</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
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 { ShippingMethod } from '../../../../core/models/shipping.model';
|
||||||
|
import { ShippingMethodService } from '../../../services/shipping-method.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-shipping-method-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, ReactiveFormsModule],
|
||||||
|
templateUrl: './shipping-method-list.component.html',
|
||||||
|
})
|
||||||
|
export class ShippingMethodListComponent implements OnInit {
|
||||||
|
private shippingMethodService = inject(ShippingMethodService);
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
|
methods$!: Observable<ShippingMethod[]>;
|
||||||
|
methodForm: FormGroup;
|
||||||
|
selectedMethodId: string | null = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.methodForm = this.fb.group({
|
||||||
|
name: ['', Validators.required],
|
||||||
|
description: [''],
|
||||||
|
cost: [0, [Validators.required, Validators.min(0)]],
|
||||||
|
isActive: [true]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void { this.loadMethods(); }
|
||||||
|
loadMethods(): void { this.methods$ = this.shippingMethodService.getAll(); }
|
||||||
|
|
||||||
|
selectMethod(method: ShippingMethod): void {
|
||||||
|
this.selectedMethodId = method.id;
|
||||||
|
this.methodForm.patchValue(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelection(): void {
|
||||||
|
this.selectedMethodId = null;
|
||||||
|
this.methodForm.reset({ isActive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.methodForm.invalid) return;
|
||||||
|
const dataToSend = { ...this.methodForm.value, id: this.selectedMethodId || '0' };
|
||||||
|
|
||||||
|
if (this.selectedMethodId) {
|
||||||
|
this.shippingMethodService.update(this.selectedMethodId, dataToSend).subscribe(() => this.reset());
|
||||||
|
} else {
|
||||||
|
this.shippingMethodService.create(dataToSend).subscribe(() => this.reset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDelete(id: string): void {
|
||||||
|
if (confirm('Versandmethode wirklich löschen?')) {
|
||||||
|
this.shippingMethodService.delete(id).subscribe(() => this.loadMethods());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private reset(): void {
|
||||||
|
this.loadMethods();
|
||||||
|
this.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Shop-Stammdaten verwalten</h1>
|
||||||
|
<form *ngIf="shopInfoForm" [formGroup]="shopInfoForm" (ngSubmit)="onSubmit()">
|
||||||
|
<input type="text" formControlName="shopName" placeholder="Shop-Name">
|
||||||
|
<input type="text" formControlName="slogan" placeholder="Slogan">
|
||||||
|
<input type="email" formControlName="contactEmail" placeholder="Kontakt E-Mail">
|
||||||
|
<input type="tel" formControlName="phoneNumber" placeholder="Telefonnummer">
|
||||||
|
<hr>
|
||||||
|
<input type="text" formControlName="street" placeholder="Straße & Hausnummer">
|
||||||
|
<input type="text" formControlName="city" placeholder="Stadt">
|
||||||
|
<input type="text" formControlName="postalCode" placeholder="PLZ">
|
||||||
|
<input type="text" formControlName="country" placeholder="Land">
|
||||||
|
<button type="submit" [disabled]="shopInfoForm.invalid">Speichern</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { Component, OnInit, inject } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { AdminShopInfo } from '../../../../core/models/shop.model';
|
||||||
|
import { ShopInfoService } from '../../../services/shop-info.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-shop-info',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, ReactiveFormsModule],
|
||||||
|
templateUrl: './shop-info.component.html',
|
||||||
|
})
|
||||||
|
export class ShopInfoComponent implements OnInit {
|
||||||
|
private shopInfoService = inject(ShopInfoService);
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
|
shopInfoForm!: FormGroup;
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.shopInfoForm = this.fb.group({
|
||||||
|
shopName: ['', Validators.required],
|
||||||
|
slogan: [''],
|
||||||
|
contactEmail: ['', [Validators.required, Validators.email]],
|
||||||
|
phoneNumber: [''],
|
||||||
|
street: [''],
|
||||||
|
city: [''],
|
||||||
|
postalCode: [''],
|
||||||
|
country: ['']
|
||||||
|
});
|
||||||
|
|
||||||
|
this.shopInfoService.get().subscribe(data => {
|
||||||
|
this.shopInfoForm.patchValue(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.shopInfoForm.invalid) return;
|
||||||
|
this.shopInfoService.update(this.shopInfoForm.value).subscribe(() => {
|
||||||
|
alert('Shop-Informationen gespeichert!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Lieferanten verwalten</h1>
|
||||||
|
|
||||||
|
<form [formGroup]="supplierForm" (ngSubmit)="onSubmit()">
|
||||||
|
<h3>
|
||||||
|
{{ selectedSupplierId ? "Lieferant bearbeiten" : "Neuer Lieferant" }}
|
||||||
|
</h3>
|
||||||
|
<input type="text" formControlName="name" placeholder="Name" />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
formControlName="contactPerson"
|
||||||
|
placeholder="Ansprechpartner"
|
||||||
|
/>
|
||||||
|
<input type="email" formControlName="email" placeholder="E-Mail" />
|
||||||
|
<input type="tel" formControlName="phoneNumber" placeholder="Telefon" />
|
||||||
|
<button type="submit" [disabled]="supplierForm.invalid">
|
||||||
|
{{ selectedSupplierId ? "Aktualisieren" : "Erstellen" }}
|
||||||
|
</button>
|
||||||
|
<button type="button" *ngIf="selectedSupplierId" (click)="clearSelection()">
|
||||||
|
Abbrechen
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<h2>Bestehende Lieferanten</h2>
|
||||||
|
<ul>
|
||||||
|
<li *ngFor="let supplier of suppliers$ | async">
|
||||||
|
{{ supplier.name }} ({{ supplier.contactPerson }})
|
||||||
|
<button (click)="selectSupplier(supplier)">Bearbeiten</button>
|
||||||
|
<button (click)="onDelete(supplier.id)">Löschen</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
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 { Supplier } from '../../../../core/models/supplier.model';
|
||||||
|
import { SupplierService } from '../../../services/supplier.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-supplier-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, ReactiveFormsModule],
|
||||||
|
templateUrl: './supplier-list.component.html',
|
||||||
|
})
|
||||||
|
export class SupplierListComponent implements OnInit {
|
||||||
|
private supplierService = inject(SupplierService);
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
|
suppliers$!: Observable<Supplier[]>;
|
||||||
|
supplierForm: FormGroup;
|
||||||
|
selectedSupplierId: string | null = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.supplierForm = this.fb.group({
|
||||||
|
name: ['', Validators.required],
|
||||||
|
contactPerson: [''],
|
||||||
|
email: ['', Validators.email],
|
||||||
|
phoneNumber: ['']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void { this.loadSuppliers(); }
|
||||||
|
loadSuppliers(): void { this.suppliers$ = this.supplierService.getAll(); }
|
||||||
|
|
||||||
|
selectSupplier(supplier: Supplier): void {
|
||||||
|
this.selectedSupplierId = supplier.id;
|
||||||
|
this.supplierForm.patchValue(supplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelection(): void {
|
||||||
|
this.selectedSupplierId = null;
|
||||||
|
this.supplierForm.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.supplierForm.invalid) return;
|
||||||
|
|
||||||
|
const dataToSend = { ...this.supplierForm.value, id: this.selectedSupplierId || '0' };
|
||||||
|
|
||||||
|
if (this.selectedSupplierId) {
|
||||||
|
this.supplierService.update(this.selectedSupplierId, dataToSend).subscribe(() => this.reset());
|
||||||
|
} else {
|
||||||
|
this.supplierService.create(dataToSend).subscribe(() => this.reset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDelete(id: string): void {
|
||||||
|
if (confirm('Lieferant wirklich löschen?')) {
|
||||||
|
this.supplierService.delete(id).subscribe(() => this.loadSuppliers());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private reset(): void {
|
||||||
|
this.loadSuppliers();
|
||||||
|
this.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Benutzer verwalten</h1>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Rollen</th>
|
||||||
|
<th>Aktionen</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let user of users$ | async">
|
||||||
|
<td>{{ user.email }}</td>
|
||||||
|
<td>{{ user.firstName }} {{ user.lastName }}</td>
|
||||||
|
<td>{{ user.roles?.join(', ') }}</td>
|
||||||
|
<td>
|
||||||
|
<!-- Hier könnte ein "Rollen bearbeiten"-Button hin -->
|
||||||
|
<button (click)="onDelete(user)">Löschen</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Component, OnInit, inject } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { User } from '../../../../core/models/user.model';
|
||||||
|
import { UserService } from '../../../services/user.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-user-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule],
|
||||||
|
templateUrl: './user-list.component.html',
|
||||||
|
})
|
||||||
|
export class UserListComponent implements OnInit {
|
||||||
|
private userService = inject(UserService);
|
||||||
|
users$!: Observable<User[]>;
|
||||||
|
|
||||||
|
ngOnInit(): void { this.loadUsers(); }
|
||||||
|
loadUsers(): void { this.users$ = this.userService.getAll(); }
|
||||||
|
|
||||||
|
onDelete(user: User): void {
|
||||||
|
if (confirm(`Benutzer ${user.email} wirklich löschen?`)) {
|
||||||
|
this.userService.delete(user.id!).subscribe(() => this.loadUsers());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ import { ButtonComponent } from '../../ui/button/button.component';
|
|||||||
import { PaginatorComponent } from '../paginator/paginator.component';
|
import { PaginatorComponent } from '../paginator/paginator.component';
|
||||||
|
|
||||||
|
|
||||||
import { OrderStatus } from '../../../../core/types/order';
|
// import { any } from '../../../../core/types/order';
|
||||||
import { SearchBarComponent } from '../../layout/search-bar/search-bar.component';
|
import { SearchBarComponent } from '../../layout/search-bar/search-bar.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -38,7 +38,7 @@ export class OrdersTableComponent {
|
|||||||
@Output() delete = new EventEmitter<string>();
|
@Output() delete = new EventEmitter<string>();
|
||||||
|
|
||||||
public searchTerm = '';
|
public searchTerm = '';
|
||||||
public selectedStatus: OrderStatus | 'all' = 'all';
|
public selectedStatus: any | 'all' = 'all';
|
||||||
|
|
||||||
public statusOptions: any[] = [
|
public statusOptions: any[] = [
|
||||||
{ value: 'all', label: 'Alle' },
|
{ value: 'all', label: 'Alle' },
|
||||||
@@ -52,7 +52,7 @@ export class OrdersTableComponent {
|
|||||||
public displayedOrders: any[] = [];
|
public displayedOrders: any[] = [];
|
||||||
public currentPage = 1;
|
public currentPage = 1;
|
||||||
|
|
||||||
private statusTextMap = new Map<OrderStatus, string>([
|
private statusTextMap = new Map<any, string>([
|
||||||
['completed', 'Abgeschlossen'],
|
['completed', 'Abgeschlossen'],
|
||||||
['processing', 'In Bearbeitung'],
|
['processing', 'In Bearbeitung'],
|
||||||
['cancelled', 'Storniert'],
|
['cancelled', 'Storniert'],
|
||||||
@@ -76,7 +76,7 @@ export class OrdersTableComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Called when a status pill is clicked
|
// Called when a status pill is clicked
|
||||||
onStatusChange(status: OrderStatus | 'all'): void {
|
onStatusChange(status: any | 'all'): void {
|
||||||
this.selectedStatus = status;
|
this.selectedStatus = status;
|
||||||
this.applyFiltersAndPagination();
|
this.applyFiltersAndPagination();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component, Input, OnChanges } from '@angular/core';
|
import { Component, Input, OnChanges } from '@angular/core';
|
||||||
import { CommonModule, NgClass } from '@angular/common';
|
import { CommonModule, NgClass } from '@angular/common';
|
||||||
import { OrderStatus } from '../../../../core/types/order';
|
// import { OrderStatus } from '../../../../core/types/order';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-status-pill',
|
selector: 'app-status-pill',
|
||||||
@@ -11,14 +11,14 @@ import { OrderStatus } from '../../../../core/types/order';
|
|||||||
})
|
})
|
||||||
export class StatusPillComponent implements OnChanges {
|
export class StatusPillComponent implements OnChanges {
|
||||||
// Nimmt jetzt den neuen, sprechenden Status entgegen
|
// Nimmt jetzt den neuen, sprechenden Status entgegen
|
||||||
@Input() status: OrderStatus = 'info';
|
@Input() status: any = 'info';
|
||||||
|
|
||||||
// Diese Eigenschaften werden vom Template verwendet
|
// Diese Eigenschaften werden vom Template verwendet
|
||||||
public displayText = '';
|
public displayText = '';
|
||||||
public cssClass = '';
|
public cssClass = '';
|
||||||
|
|
||||||
// Eine Map, die Statusnamen auf Text und CSS-Klasse abbildet
|
// Eine Map, die Statusnamen auf Text und CSS-Klasse abbildet
|
||||||
private statusMap = new Map<OrderStatus, { text: string, css: string }>([
|
private statusMap = new Map<any, { text: string, css: string }>([
|
||||||
['completed', { text: 'Abgeschlossen', css: 'pill-success' }],
|
['completed', { text: 'Abgeschlossen', css: 'pill-success' }],
|
||||||
['processing', { text: 'In Bearbeitung', css: 'pill-warning' }],
|
['processing', { text: 'In Bearbeitung', css: 'pill-warning' }],
|
||||||
['cancelled', { text: 'Storniert', css: 'pill-danger' }],
|
['cancelled', { text: 'Storniert', css: 'pill-danger' }],
|
||||||
|
|||||||
Reference in New Issue
Block a user