refactor: rename components and update dialog implementations; add confirm dialog for deletion actions
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
.auth-wrap {
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.auth-card {
|
||||
width: 100%;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
margin: 8px;
|
||||
|
||||
button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.ml-8 {
|
||||
margin-left: 8px;
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
<section class="auth-wrap">
|
||||
<mat-card class="auth-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Ajouter un produit</mat-card-title>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
<form [formGroup]="addProductForm" (ngSubmit)="onProductAdd()" class="form-grid">
|
||||
|
||||
<!-- Title -->
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Titre</mat-label>
|
||||
<input matInput
|
||||
id="title"
|
||||
name="title"
|
||||
formControlName="title"
|
||||
type="text"
|
||||
required>
|
||||
@if (isFieldInvalid('title')) {
|
||||
<mat-error>{{ getFieldError('title') }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Description -->
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Description</mat-label>
|
||||
<input matInput
|
||||
id="description"
|
||||
name="description"
|
||||
formControlName="description"
|
||||
type="text"
|
||||
required>
|
||||
@if (isFieldInvalid('description')) {
|
||||
<mat-error>{{ getFieldError('description') }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Category -->
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Catégorie</mat-label>
|
||||
<mat-select formControlName="category" disableRipple>
|
||||
@for (category of categories; track category.id) {
|
||||
<mat-option [value]="category">{{ category.name }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Condition -->
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>État</mat-label>
|
||||
<mat-select formControlName="condition" disableRipple>
|
||||
@for (condition of conditions; track condition.id) {
|
||||
<mat-option [value]="condition">{{ condition.displayName }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Brand -->
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Marque</mat-label>
|
||||
<mat-select formControlName="brand" [compareWith]="compareById" disableRipple>
|
||||
@for (brand of filteredBrands; track brand.id) {
|
||||
<mat-option [value]="brand.id">{{ brand.name }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Platform -->
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Plateforme</mat-label>
|
||||
<mat-select formControlName="platform" [compareWith]="compareById" disableRipple>
|
||||
@for (platform of filteredPlatforms; track platform.id) {
|
||||
<mat-option [value]="platform.id">{{ platform.name }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Complete state -->
|
||||
<mat-checkbox formControlName="complete" id="complete">
|
||||
Complet
|
||||
</mat-checkbox>
|
||||
@if (isFieldInvalid('complete')) {
|
||||
<div class="mat-caption mat-error">{{ getFieldError('complete') }}</div>
|
||||
}
|
||||
|
||||
<!-- manual included -->
|
||||
<mat-checkbox formControlName="manual" id="manual">
|
||||
Avec notice
|
||||
</mat-checkbox>
|
||||
@if (isFieldInvalid('manual')) {
|
||||
<div class="mat-caption mat-error">{{ getFieldError('manual') }}</div>
|
||||
}
|
||||
|
||||
<!-- Price -->
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Prix TTC</mat-label>
|
||||
<input matInput
|
||||
id="price"
|
||||
name="price"
|
||||
formControlName="price"
|
||||
type="text"
|
||||
required>
|
||||
@if (isFieldInvalid('price')) {
|
||||
<mat-error>{{ getFieldError('price') }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Quantity -->
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Quantité</mat-label>
|
||||
<input matInput
|
||||
id="quantity"
|
||||
name="quantity"
|
||||
formControlName="quantity"
|
||||
type="text"
|
||||
required>
|
||||
@if (isFieldInvalid('quantity')) {
|
||||
<mat-error>{{ getFieldError('quantity') }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div class="actions">
|
||||
<button mat-raised-button color="primary"
|
||||
type="submit"
|
||||
[disabled]="isLoading || addProductForm.invalid">
|
||||
@if (isLoading) {
|
||||
<mat-progress-spinner diameter="16" mode="indeterminate"></mat-progress-spinner>
|
||||
<span class="ml-8">Ajout du produit…</span>
|
||||
} @else {
|
||||
Ajouter le produit
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<mat-card-actions align="end">
|
||||
<span class="mat-body-small">
|
||||
<a [routerLink]="'/login'">Voir la liste des produits</a>
|
||||
</span>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</section>
|
||||
@@ -1,345 +0,0 @@
|
||||
import {Component, inject, OnDestroy, OnInit} from '@angular/core';
|
||||
import {
|
||||
AbstractControl,
|
||||
FormBuilder,
|
||||
FormGroup,
|
||||
FormsModule,
|
||||
ReactiveFormsModule, ValidatorFn,
|
||||
Validators
|
||||
} from "@angular/forms";
|
||||
import {MatButton} from "@angular/material/button";
|
||||
import {
|
||||
MatCard,
|
||||
MatCardActions,
|
||||
MatCardContent,
|
||||
MatCardHeader,
|
||||
MatCardTitle
|
||||
} from "@angular/material/card";
|
||||
import {MatCheckbox} from "@angular/material/checkbox";
|
||||
import {MatDivider} from "@angular/material/divider";
|
||||
import {MatError, MatFormField, MatLabel} from "@angular/material/form-field";
|
||||
import {MatInput} from "@angular/material/input";
|
||||
import {MatProgressSpinner} from "@angular/material/progress-spinner";
|
||||
import {MatOption, MatSelect} from '@angular/material/select';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {BrandService} from '../../services/app/brand.service';
|
||||
import {Brand} from '../../interfaces/brand';
|
||||
import {PlatformService} from '../../services/app/platform.service';
|
||||
import {Platform} from '../../interfaces/platform';
|
||||
import {Category} from '../../interfaces/category';
|
||||
import {CategoryService} from '../../services/app/category.service';
|
||||
import {ConditionService} from '../../services/app/condition.service';
|
||||
import {Condition} from '../../interfaces/condition';
|
||||
import {ProductService} from '../../services/app/product.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-product',
|
||||
standalone: true,
|
||||
imports: [
|
||||
FormsModule,
|
||||
MatButton,
|
||||
MatCard,
|
||||
MatCardActions,
|
||||
MatCardContent,
|
||||
MatCardHeader,
|
||||
MatCardTitle,
|
||||
MatCheckbox,
|
||||
MatDivider,
|
||||
MatError,
|
||||
MatFormField,
|
||||
MatInput,
|
||||
MatLabel,
|
||||
MatProgressSpinner,
|
||||
ReactiveFormsModule,
|
||||
MatSelect,
|
||||
MatOption,
|
||||
RouterLink
|
||||
],
|
||||
templateUrl: './add-product.component.html',
|
||||
styleUrl: './add-product.component.css'
|
||||
})
|
||||
export class AddProductComponent implements OnInit, OnDestroy {
|
||||
|
||||
addProductForm: FormGroup;
|
||||
isSubmitted = false;
|
||||
isLoading = false;
|
||||
|
||||
brands: Brand[] = [];
|
||||
platforms: Platform[] = [];
|
||||
categories: Category[] = [];
|
||||
conditions: Condition[] = [];
|
||||
|
||||
filteredBrands: Brand[] = [];
|
||||
filteredPlatforms: Platform[] = [];
|
||||
|
||||
private addProductSubscription: Subscription | null = null;
|
||||
|
||||
private brandControlSubscription: Subscription | null = null;
|
||||
private platformControlSubscription: Subscription | null = null;
|
||||
|
||||
private brandSubscription: Subscription | null = null;
|
||||
private platformSubscription: Subscription | null = null;
|
||||
private categorySubscription: Subscription | null = null;
|
||||
private conditionSubscription: Subscription | null = null;
|
||||
|
||||
private readonly brandService: BrandService = inject(BrandService);
|
||||
private readonly platformService = inject(PlatformService);
|
||||
private readonly categoryService = inject(CategoryService);
|
||||
private readonly conditionService = inject(ConditionService);
|
||||
|
||||
private readonly productService = inject(ProductService);
|
||||
|
||||
constructor(private readonly formBuilder: FormBuilder) {
|
||||
this.addProductForm = this.formBuilder.group({
|
||||
title: ['', [
|
||||
Validators.required,
|
||||
Validators.minLength(3),
|
||||
Validators.maxLength(50),
|
||||
Validators.pattern(/^[\p{L}\p{N}\s]+$/u)
|
||||
]],
|
||||
description: ['', [
|
||||
Validators.required,
|
||||
Validators.minLength(10),
|
||||
Validators.maxLength(255),
|
||||
Validators.pattern(/^[\p{L}\p{N}\s]+$/u)
|
||||
]],
|
||||
category: ['', [
|
||||
Validators.required
|
||||
]],
|
||||
condition: ['', [
|
||||
Validators.required
|
||||
]],
|
||||
// stocker des ids (string|number) dans les controls
|
||||
brand: ['', [
|
||||
Validators.required
|
||||
]],
|
||||
platform: ['', [
|
||||
Validators.required
|
||||
]],
|
||||
complete: [true],
|
||||
manual: [true],
|
||||
price: ['', [
|
||||
Validators.required,
|
||||
Validators.pattern(/^\d+([.,]\d{1,2})?$/),
|
||||
this.priceRangeValidator(0, 9999)
|
||||
]],
|
||||
quantity: ['', [
|
||||
Validators.required,
|
||||
Validators.min(1),
|
||||
Validators.max(999),
|
||||
Validators.pattern(/^\d+$/)
|
||||
]]
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private normalizeIds<T extends Record<string, any>>(items: T[] | undefined, idKey = 'id'): T[] {
|
||||
return (items || []).map((it, i) => ({
|
||||
...it,
|
||||
[idKey]: (it[idKey] ?? i)
|
||||
}));
|
||||
}
|
||||
|
||||
private getPlatformBrandId(platform: any): string | number | undefined {
|
||||
if (!platform) return undefined;
|
||||
const maybe = platform.brand ?? platform['brand_id'] ?? platform['brandId'];
|
||||
if (maybe == null) return undefined;
|
||||
|
||||
if (typeof maybe === 'object') {
|
||||
if (maybe.id != null) return maybe.id;
|
||||
if (maybe.name != null) {
|
||||
const found = this.brands.find(b =>
|
||||
String(b.name).toLowerCase() === String(maybe.name).toLowerCase()
|
||||
|| String(b.id) === String(maybe.name)
|
||||
);
|
||||
return found?.id;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const asStr = String(maybe);
|
||||
const match = this.brands.find(b =>
|
||||
String(b.id) === asStr || String(b.name).toLowerCase() === asStr.toLowerCase()
|
||||
);
|
||||
return match?.id ?? maybe;
|
||||
}
|
||||
|
||||
private priceRangeValidator(min: number, max: number): ValidatorFn {
|
||||
return (control: AbstractControl) => {
|
||||
const val = control.value;
|
||||
if (val === null || val === undefined || val === '') return null;
|
||||
const normalized = String(val).replace(',', '.').trim();
|
||||
const num = Number.parseFloat(normalized);
|
||||
if (Number.isNaN(num)) return {pattern: true};
|
||||
return (num < min || num > max) ? {range: {min, max, actual: num}} : null;
|
||||
};
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
this.brandSubscription = this.brandService.getAll().subscribe({
|
||||
next: (brands: Brand[]) => {
|
||||
this.brands = this.normalizeIds(brands, 'id');
|
||||
this.filteredBrands = [...this.brands];
|
||||
},
|
||||
error: (error: any) => {
|
||||
console.error('Error fetching brands:', error);
|
||||
},
|
||||
complete: () => {
|
||||
console.log('Finished fetching brands:', this.brands);
|
||||
}
|
||||
});
|
||||
|
||||
this.platformSubscription = this.platformService.getAll().subscribe({
|
||||
next: (platforms: Platform[]) => {
|
||||
this.platforms = this.normalizeIds(platforms, 'id');
|
||||
this.filteredPlatforms = [...this.platforms];
|
||||
},
|
||||
error: (error: any) => {
|
||||
console.error('Error fetching platforms:', error);
|
||||
},
|
||||
complete: () => {
|
||||
console.log('Finished fetching platforms:', this.platforms);
|
||||
}
|
||||
});
|
||||
|
||||
this.categorySubscription = this.categoryService.getAll().subscribe({
|
||||
next: (categories: Category[]) => {
|
||||
this.categories = this.normalizeIds(categories, 'id');
|
||||
},
|
||||
error: (error: any) => {
|
||||
console.error('Error fetching categories:', error);
|
||||
},
|
||||
complete: () => {
|
||||
console.log('Finished fetching categories:', this.categories);
|
||||
}
|
||||
});
|
||||
|
||||
this.conditionSubscription = this.conditionService.getConditions().subscribe({
|
||||
next: (conditions: Condition[]) => {
|
||||
this.conditions = this.normalizeIds(conditions, 'id');
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error fetching conditions:', error);
|
||||
},
|
||||
complete: () => {
|
||||
console.log('Finished fetching conditions:', this.conditions);
|
||||
}
|
||||
});
|
||||
|
||||
const brandControl = this.addProductForm.get('brand');
|
||||
const platformControl = this.addProductForm.get('platform');
|
||||
|
||||
this.brandControlSubscription = brandControl?.valueChanges.subscribe((brandId) => {
|
||||
if (brandId != null && brandId !== '') {
|
||||
const brandIdStr = String(brandId);
|
||||
this.filteredPlatforms = this.platforms.filter(p => {
|
||||
const pBid = this.getPlatformBrandId(p);
|
||||
return pBid != null && String(pBid) === brandIdStr;
|
||||
});
|
||||
const curPlatformId = platformControl?.value;
|
||||
if (curPlatformId != null && !this.filteredPlatforms.some(p => String(p.id) === String(curPlatformId))) {
|
||||
platformControl?.setValue(null);
|
||||
}
|
||||
} else {
|
||||
this.filteredPlatforms = [...this.platforms];
|
||||
}
|
||||
}) ?? null;
|
||||
|
||||
this.platformControlSubscription = platformControl?.valueChanges.subscribe((platformId) => {
|
||||
if (platformId != null && platformId !== '') {
|
||||
const platformObj = this.platforms.find(p => String(p.id) === String(platformId));
|
||||
const pBrandId = this.getPlatformBrandId(platformObj);
|
||||
if (pBrandId != null) {
|
||||
const pBrandIdStr = String(pBrandId);
|
||||
this.filteredBrands = this.brands.filter(b => String(b.id) === pBrandIdStr);
|
||||
const curBrandId = brandControl?.value;
|
||||
if (curBrandId != null && String(curBrandId) !== pBrandIdStr) {
|
||||
brandControl?.setValue(null);
|
||||
}
|
||||
} else {
|
||||
this.filteredBrands = [...this.brands];
|
||||
}
|
||||
} else {
|
||||
this.filteredBrands = [...this.brands];
|
||||
}
|
||||
}) ?? null;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.addProductSubscription?.unsubscribe();
|
||||
this.brandControlSubscription?.unsubscribe();
|
||||
this.platformControlSubscription?.unsubscribe();
|
||||
this.brandSubscription?.unsubscribe();
|
||||
this.platformSubscription?.unsubscribe();
|
||||
this.categorySubscription?.unsubscribe();
|
||||
this.conditionSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
onProductAdd() {
|
||||
this.isSubmitted = true;
|
||||
|
||||
if (this.addProductForm.valid) {
|
||||
this.isLoading = true;
|
||||
const raw = this.addProductForm.value;
|
||||
|
||||
const priceStr = raw.price ?? '';
|
||||
const priceNum = Number(String(priceStr).replace(',', '.').trim());
|
||||
if (Number.isNaN(priceNum)) {
|
||||
this.isLoading = false;
|
||||
this.addProductForm.get('price')?.setErrors({pattern: true});
|
||||
return;
|
||||
}
|
||||
|
||||
const quantityNum = Number(raw.quantity);
|
||||
|
||||
const payload = {
|
||||
...raw,
|
||||
price: priceNum,
|
||||
quantity: quantityNum
|
||||
};
|
||||
|
||||
this.addProductSubscription = this.productService.addProduct(payload).subscribe({
|
||||
next: (response) => {
|
||||
console.log("Product added successfully:", response);
|
||||
this.addProductForm.reset();
|
||||
this.isSubmitted = false;
|
||||
alert("Produit ajouté avec succès !");
|
||||
},
|
||||
error: (error) => {
|
||||
console.error("Error adding product:", error);
|
||||
alert("Une erreur est survenue lors de l'ajout du produit.");
|
||||
},
|
||||
complete: () => {
|
||||
this.isLoading = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isFieldInvalid(fieldName: string): boolean {
|
||||
const field = this.addProductForm.get(fieldName);
|
||||
return Boolean(field && field.invalid && (field.dirty || field.touched || this.isSubmitted));
|
||||
}
|
||||
|
||||
getFieldError(fieldName: string): string {
|
||||
const field = this.addProductForm.get(fieldName);
|
||||
|
||||
if (field && field.errors) {
|
||||
if (field.errors['required']) return `Ce champ est obligatoire`;
|
||||
if (field.errors['email']) return `Format d'email invalide`;
|
||||
if (field.errors['minlength']) return `Minimum ${field.errors['minlength'].requiredLength} caractères`;
|
||||
if (field.errors['maxlength']) return `Maximum ${field.errors['maxlength'].requiredLength} caractères`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
compareById = (a: any, b: any) => {
|
||||
if (a == null || b == null) return a === b;
|
||||
if (typeof a !== 'object' || typeof b !== 'object') {
|
||||
return String(a) === String(b);
|
||||
}
|
||||
return String(a.id ?? a) === String(b.id ?? b);
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {AdminNavbarComponent} from '../../components/admin-navbar/admin-navbar.component';
|
||||
import {AdminNavbarComponent} from '../../components/navbar/admin-navbar/admin-navbar.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin',
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
<h1>Bonjour, {{ user.firstName }}!</h1>
|
||||
<p>Que souhaitez-vous faire ?</p>
|
||||
<br>
|
||||
<button mat-flat-button [routerLink]="'/add-product'">Ajouter un nouveau produit</button>
|
||||
<button mat-raised-button [routerLink]="'/products'">Voir la liste des produits</button>
|
||||
<div class="home-actions">
|
||||
<button mat-flat-button [routerLink]="'/products'">Voir la liste des produits</button>
|
||||
<button mat-raised-button [routerLink]="'/admin'">Gérer la base de données</button>
|
||||
</div>
|
||||
} @else {
|
||||
<h2>Gestion des produits</h2>
|
||||
<div class="home-actions">
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HomeComponent } from './home.component';
|
||||
|
||||
describe('HomeComponent', () => {
|
||||
let component: HomeComponent;
|
||||
let fixture: ComponentFixture<HomeComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [HomeComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HomeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,16 +1,14 @@
|
||||
import {Component, inject} from '@angular/core';
|
||||
import {MatButton} from '@angular/material/button';
|
||||
import {AuthService} from '../../services/auth/auth.service';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {AddProductComponent} from '../add-product/add-product.component';
|
||||
import {Router, RouterLink} from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatButton,
|
||||
RouterLink,
|
||||
AddProductComponent
|
||||
RouterLink
|
||||
],
|
||||
templateUrl: './home.component.html',
|
||||
styleUrl: './home.component.css'
|
||||
@@ -18,6 +16,7 @@ import {AddProductComponent} from '../add-product/add-product.component';
|
||||
export class HomeComponent {
|
||||
|
||||
protected readonly authService: AuthService = inject(AuthService);
|
||||
protected readonly router: Router = inject(Router);
|
||||
|
||||
getUser() {
|
||||
return this.authService.user();
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoginComponent } from './login.component';
|
||||
|
||||
describe('LoginComponent', () => {
|
||||
let component: LoginComponent;
|
||||
let fixture: ComponentFixture<LoginComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [LoginComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(LoginComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -50,12 +50,11 @@ export class LoginComponent implements OnDestroy {
|
||||
this.loginSubscription = this.authService.login(
|
||||
this.loginFormGroup.value as Credentials).subscribe({
|
||||
next: (result: User | null | undefined) => {
|
||||
console.log(result);
|
||||
this.navigateHome();
|
||||
alert('Login successful!');
|
||||
},
|
||||
error: (error) => {
|
||||
console.log(error);
|
||||
alert(error.message);
|
||||
this.invalidCredentials = true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NotFoundComponent } from './not-found.component';
|
||||
|
||||
describe('NotFoundComponent', () => {
|
||||
let component: NotFoundComponent;
|
||||
let fixture: ComponentFixture<NotFoundComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [NotFoundComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(NotFoundComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1 +1,7 @@
|
||||
<app-products-list></app-products-list>
|
||||
<ng-container>
|
||||
@if (showList) {
|
||||
<app-product-list></app-product-list>
|
||||
}
|
||||
</ng-container>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -1,17 +1,43 @@
|
||||
import {
|
||||
Component,
|
||||
Component, inject,
|
||||
} from '@angular/core';
|
||||
import {ProductsListComponent} from '../../components/products-list/products-list.component';
|
||||
import {ProductListComponent} from '../../components/list/product-list/product-list.component';
|
||||
import {ActivatedRoute, NavigationEnd, Router, RouterOutlet} from '@angular/router';
|
||||
import {filter, Subscription} from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-products',
|
||||
selector: 'app-dialog',
|
||||
templateUrl: './products.component.html',
|
||||
standalone: true,
|
||||
imports: [
|
||||
ProductsListComponent
|
||||
ProductListComponent,
|
||||
RouterOutlet
|
||||
],
|
||||
styleUrls: ['./products.component.css']
|
||||
})
|
||||
export class ProductsComponent {
|
||||
|
||||
showList = true;
|
||||
private sub?: Subscription;
|
||||
private readonly router: Router = inject(Router);
|
||||
private readonly route: ActivatedRoute = inject(ActivatedRoute);
|
||||
|
||||
ngOnInit(): void {
|
||||
this.updateShowList(this.route);
|
||||
this.sub = this.router.events.pipe(
|
||||
filter(evt => evt instanceof NavigationEnd)
|
||||
).subscribe(() => this.updateShowList(this.route));
|
||||
}
|
||||
|
||||
private updateShowList(route: ActivatedRoute): void {
|
||||
let current = route;
|
||||
while (current.firstChild) {
|
||||
current = current.firstChild;
|
||||
}
|
||||
this.showList = current === route;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.sub?.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
<mat-icon>account_circle</mat-icon>
|
||||
</div>
|
||||
<mat-card-title>{{ user.firstName }} {{ user.lastName }}</mat-card-title>
|
||||
<mat-card-subtitle>{{ user.username }} ({{ user.role }})</mat-card-subtitle>
|
||||
@if (user.role == "Administrator") {
|
||||
<mat-card-subtitle>{{ user.username }} ({{ user.role }})</mat-card-subtitle>
|
||||
} @else {
|
||||
<mat-card-subtitle>{{ user.username }}</mat-card-subtitle>
|
||||
}
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProfileComponent } from './profile.component';
|
||||
|
||||
describe('ProfileComponent', () => {
|
||||
let component: ProfileComponent;
|
||||
let fixture: ComponentFixture<ProfileComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ProfileComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ProfileComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user