diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index 6659729..ab8a3a0 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -1,2 +1,2 @@ - + diff --git a/client/src/app/app.component.spec.ts b/client/src/app/app.component.spec.ts deleted file mode 100644 index 36f4316..0000000 --- a/client/src/app/app.component.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [AppComponent], - }).compileComponents(); - }); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have the 'client' title`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('client'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain('Hello, client'); - }); -}); diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 33285ac..03410b1 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; -import {NavbarComponent} from './components/navbar/navbar.component'; +import {MainNavbarComponent} from './components/navbar/main-navbar/main-navbar.component'; @Component({ selector: 'app-root', standalone: true, - imports: [RouterOutlet, NavbarComponent], + imports: [RouterOutlet, MainNavbarComponent], templateUrl: './app.component.html', styleUrl: './app.component.css' }) diff --git a/client/src/app/app.routes.ts b/client/src/app/app.routes.ts index c40560e..064ceea 100644 --- a/client/src/app/app.routes.ts +++ b/client/src/app/app.routes.ts @@ -1,4 +1,4 @@ -import { Routes } from '@angular/router'; +import {Routes} from '@angular/router'; import {HomeComponent} from './pages/home/home.component'; import {RegisterComponent} from './pages/register/register.component'; import {LoginComponent} from './pages/login/login.component'; @@ -7,19 +7,18 @@ import {guestOnlyCanActivate, guestOnlyCanMatch} from './guards/guest-only.guard import {authOnlyCanActivate, authOnlyCanMatch} from './guards/auth-only.guard'; import {AdminComponent} from './pages/admin/admin.component'; import {adminOnlyCanActivate, adminOnlyCanMatch} from './guards/admin-only.guard'; -import {AddProductComponent} from './pages/add-product/add-product.component'; import {ProductsComponent} from './pages/products/products.component'; export const routes: Routes = [ { - path : '', + path: '', children: [ { - path : '', + path: '', component: HomeComponent }, { - path : 'home', + path: 'home', component: HomeComponent } ] @@ -31,38 +30,32 @@ export const routes: Routes = [ canActivate: [guestOnlyCanActivate] }, { - path : 'login', + path: 'login', component: LoginComponent, canMatch: [guestOnlyCanMatch], canActivate: [guestOnlyCanActivate] }, { - path : 'profile', + path: 'profile', component: ProfileComponent, canMatch: [authOnlyCanMatch], canActivate: [authOnlyCanMatch] }, { - path : 'admin', + path: 'admin', component: AdminComponent, canMatch: [adminOnlyCanMatch], canActivate: [adminOnlyCanActivate] }, { - path : 'products', + path: 'products', component: ProductsComponent, canMatch: [authOnlyCanMatch], - canActivate: [authOnlyCanActivate] + canActivate: [authOnlyCanActivate], }, { - path : 'add-product', - component: AddProductComponent, - canMatch: [authOnlyCanMatch], - canActivate: [authOnlyCanActivate] - }, - { - path : '**', + path: '**', redirectTo: '' } ]; diff --git a/client/src/app/components/brand-list/brand-list.component.html b/client/src/app/components/brand-list/brand-list.component.html deleted file mode 100644 index d2e8ec9..0000000 --- a/client/src/app/components/brand-list/brand-list.component.html +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/client/src/app/components/category-list/category-list.component.html b/client/src/app/components/category-list/category-list.component.html deleted file mode 100644 index 3783ce7..0000000 --- a/client/src/app/components/category-list/category-list.component.html +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/client/src/app/components/admin-navbar/admin-navbar.component.css b/client/src/app/components/dialog/confirm-dialog/confirm-dialog.component.css similarity index 100% rename from client/src/app/components/admin-navbar/admin-navbar.component.css rename to client/src/app/components/dialog/confirm-dialog/confirm-dialog.component.css diff --git a/client/src/app/components/dialog/confirm-dialog/confirm-dialog.component.html b/client/src/app/components/dialog/confirm-dialog/confirm-dialog.component.html new file mode 100644 index 0000000..76403eb --- /dev/null +++ b/client/src/app/components/dialog/confirm-dialog/confirm-dialog.component.html @@ -0,0 +1,8 @@ +

{{ data.title ?? 'Confirmation' }}

+ +

{{ data.message ?? 'Êtes-vous sûr·e ?' }}

+
+ + + + diff --git a/client/src/app/components/dialog/confirm-dialog/confirm-dialog.component.ts b/client/src/app/components/dialog/confirm-dialog/confirm-dialog.component.ts new file mode 100644 index 0000000..a65c0d1 --- /dev/null +++ b/client/src/app/components/dialog/confirm-dialog/confirm-dialog.component.ts @@ -0,0 +1,21 @@ +import { Component, Inject } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; + +@Component({ + selector: 'app-confirm-dialog', + standalone: true, + imports: [CommonModule, MatDialogModule, MatButtonModule], + templateUrl: './confirm-dialog.component.html', +}) +export class ConfirmDialogComponent { + constructor( + private readonly dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { title?: string; message?: string } + ) {} + + close(result: boolean) { + this.dialogRef.close(result); + } +} diff --git a/client/src/app/components/generic-dialog/generic-dialog.component.css b/client/src/app/components/dialog/generic-dialog/generic-dialog.component.css similarity index 100% rename from client/src/app/components/generic-dialog/generic-dialog.component.css rename to client/src/app/components/dialog/generic-dialog/generic-dialog.component.css diff --git a/client/src/app/components/generic-dialog/generic-dialog.component.html b/client/src/app/components/dialog/generic-dialog/generic-dialog.component.html similarity index 95% rename from client/src/app/components/generic-dialog/generic-dialog.component.html rename to client/src/app/components/dialog/generic-dialog/generic-dialog.component.html index 0a49caa..f13a2e3 100644 --- a/client/src/app/components/generic-dialog/generic-dialog.component.html +++ b/client/src/app/components/dialog/generic-dialog/generic-dialog.component.html @@ -13,7 +13,7 @@ {{ f.label }} - @let opts = (f.options$ | async) ?? f.options ?? []; + @let opts = (f.options ?? (f.options$ | async) ?? []); @for (opt of opts; track $index) { diff --git a/client/src/app/components/generic-dialog/generic-dialog.component.ts b/client/src/app/components/dialog/generic-dialog/generic-dialog.component.ts similarity index 94% rename from client/src/app/components/generic-dialog/generic-dialog.component.ts rename to client/src/app/components/dialog/generic-dialog/generic-dialog.component.ts index 66b19b5..ebea0cd 100644 --- a/client/src/app/components/generic-dialog/generic-dialog.component.ts +++ b/client/src/app/components/dialog/generic-dialog/generic-dialog.component.ts @@ -36,12 +36,12 @@ type Field = { }) export class GenericDialogComponent implements OnInit { form!: FormGroup; - fields: Field[] = []; + fields?: Field[]; constructor( private readonly fb: FormBuilder, private readonly dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: { item?: any; fields?: Field[]; title?: string } + @Inject(MAT_DIALOG_DATA) public data?: { item?: any; fields?: Field[]; title?: string } ) { } diff --git a/client/src/app/components/brand-list/brand-list.component.css b/client/src/app/components/list/brand-list/brand-list.component.css similarity index 100% rename from client/src/app/components/brand-list/brand-list.component.css rename to client/src/app/components/list/brand-list/brand-list.component.css diff --git a/client/src/app/components/list/brand-list/brand-list.component.html b/client/src/app/components/list/brand-list/brand-list.component.html new file mode 100644 index 0000000..1dd9dd7 --- /dev/null +++ b/client/src/app/components/list/brand-list/brand-list.component.html @@ -0,0 +1,9 @@ + + diff --git a/client/src/app/components/brand-list/brand-list.component.ts b/client/src/app/components/list/brand-list/brand-list.component.ts similarity index 88% rename from client/src/app/components/brand-list/brand-list.component.ts rename to client/src/app/components/list/brand-list/brand-list.component.ts index bd70479..98e6acc 100644 --- a/client/src/app/components/brand-list/brand-list.component.ts +++ b/client/src/app/components/list/brand-list/brand-list.component.ts @@ -1,7 +1,7 @@ import { Component, inject } from '@angular/core'; -import {BrandService} from '../../services/app/brand.service'; +import {BrandService} from '../../../services/app/brand.service'; import {GenericListComponent} from '../generic-list/generic-list.component'; @Component({ diff --git a/client/src/app/components/list/category-list/category-list.component.html b/client/src/app/components/list/category-list/category-list.component.html new file mode 100644 index 0000000..69a9f5e --- /dev/null +++ b/client/src/app/components/list/category-list/category-list.component.html @@ -0,0 +1,9 @@ + + diff --git a/client/src/app/components/category-list/category-list.component.ts b/client/src/app/components/list/category-list/category-list.component.ts similarity index 87% rename from client/src/app/components/category-list/category-list.component.ts rename to client/src/app/components/list/category-list/category-list.component.ts index ea41bf4..09387e5 100644 --- a/client/src/app/components/category-list/category-list.component.ts +++ b/client/src/app/components/list/category-list/category-list.component.ts @@ -2,7 +2,7 @@ import { Component, inject } from '@angular/core'; import {GenericListComponent} from '../generic-list/generic-list.component'; -import {CategoryService} from '../../services/app/category.service'; +import {CategoryService} from '../../../services/app/category.service'; @Component({ selector: 'app-category-list', diff --git a/client/src/app/components/category-list/category.component.css b/client/src/app/components/list/category-list/category.component.css similarity index 100% rename from client/src/app/components/category-list/category.component.css rename to client/src/app/components/list/category-list/category.component.css diff --git a/client/src/app/components/generic-list/generic-list.component.css b/client/src/app/components/list/generic-list/generic-list.component.css similarity index 57% rename from client/src/app/components/generic-list/generic-list.component.css rename to client/src/app/components/list/generic-list/generic-list.component.css index 1175006..2324320 100644 --- a/client/src/app/components/generic-list/generic-list.component.css +++ b/client/src/app/components/list/generic-list/generic-list.component.css @@ -15,7 +15,7 @@ justify-content: space-between; gap: 1rem; flex-wrap: wrap; - border-bottom: 1px solid rgba(0,0,0,.08); + border-bottom: 1px solid rgba(0, 0, 0, .08); padding-bottom: .75rem; } @@ -27,12 +27,11 @@ /* ===== Cartes (filtre, tableau, pagination) partagent le même style ===== */ .gl-block { - border: 1px solid rgba(0,0,0,.08); + border: 1px solid rgba(0, 0, 0, .08); border-radius: 12px; background: var(--gl-surface, #fff); - box-shadow: - 0 1px 2px rgba(0,0,0,.04), - 0 2px 8px rgba(0,0,0,.06); + box-shadow: 0 1px 2px rgba(0, 0, 0, .04), + 0 2px 8px rgba(0, 0, 0, .06); } /* ===== Barre de filtre ===== */ @@ -66,7 +65,7 @@ top: 0; z-index: 2; background: inherit; - box-shadow: inset 0 -1px 0 rgba(0,0,0,.08); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .08); } /* Cellules */ @@ -80,8 +79,13 @@ } /* Zebra + hover */ -.gl-table tr.mat-mdc-row:nth-child(odd) td[mat-cell] { background: rgba(0,0,0,.015); } -.gl-table tr.mat-mdc-row:hover td[mat-cell] { background: rgba(0,0,0,.035); } +.gl-table tr.mat-mdc-row:nth-child(odd) td[mat-cell] { + background: rgba(0, 0, 0, .015); +} + +.gl-table tr.mat-mdc-row:hover td[mat-cell] { + background: rgba(0, 0, 0, .035); +} /* Actions */ .actions-cell { @@ -90,42 +94,78 @@ justify-content: center; gap: .4rem; } -.actions-cell .mat-mdc-icon-button { width: 40px; height: 40px; } + +.actions-cell .mat-mdc-icon-button { + width: 40px; + height: 40px; +} /* ===== Pagination ===== */ .gl-paginator-wrap { padding: .25rem .5rem; } + .gl-paginator { margin-top: .25rem; padding-top: .5rem; - border-top: 1px solid rgba(0,0,0,.08); + border-top: 1px solid rgba(0, 0, 0, .08); display: flex; justify-content: flex-end; } /* ===== Responsive ===== */ @media (max-width: 799px) { - .generic-list { padding: 0.75rem 1rem; } - .gl-header { flex-direction: column; align-items: stretch; gap: 0.75rem; } - .gl-table { min-width: 0; } + .generic-list { + padding: 0.75rem 1rem; + } + + .gl-header { + flex-direction: column; + align-items: stretch; + gap: 0.75rem; + } + + .gl-table { + min-width: 0; + } + .gl-table th[mat-header-cell], - .gl-table td[mat-cell] { white-space: normal; padding: 10px 12px; } - .actions-cell { justify-content: flex-start; } + .gl-table td[mat-cell] { + white-space: normal; + padding: 10px 12px; + } + + .actions-cell { + justify-content: flex-start; + } } /* ===== Dark mode ===== */ @media (prefers-color-scheme: dark) { .gl-block { background: #1b1b1b; - border-color: rgba(255,255,255,.08); - box-shadow: - 0 1px 2px rgba(0,0,0,.6), - 0 2px 8px rgba(0,0,0,.45); + border-color: rgba(255, 255, 255, .08); + box-shadow: 0 1px 2px rgba(0, 0, 0, .6), + 0 2px 8px rgba(0, 0, 0, .45); + } + + .gl-header { + border-bottom-color: rgba(255, 255, 255, .08); + } + + .gl-table th[mat-header-cell] { + box-shadow: inset 0 -1px 0 rgba(255, 255, 255, .08); + } + + .gl-table tr.mat-mdc-row:nth-child(odd) td[mat-cell] { + background: rgba(255, 255, 255, .025); + } + + .gl-table tr.mat-mdc-row:hover td[mat-cell] { + background: rgba(255, 255, 255, .06); + } + + .gl-paginator { + border-top-color: rgba(255, 255, 255, .08); } - .gl-header { border-bottom-color: rgba(255,255,255,.08); } - .gl-table th[mat-header-cell] { box-shadow: inset 0 -1px 0 rgba(255,255,255,.08); } - .gl-table tr.mat-mdc-row:nth-child(odd) td[mat-cell] { background: rgba(255,255,255,.025); } - .gl-table tr.mat-mdc-row:hover td[mat-cell] { background: rgba(255,255,255,.06); } - .gl-paginator { border-top-color: rgba(255,255,255,.08); } } diff --git a/client/src/app/components/generic-list/generic-list.component.html b/client/src/app/components/list/generic-list/generic-list.component.html similarity index 95% rename from client/src/app/components/generic-list/generic-list.component.html rename to client/src/app/components/list/generic-list/generic-list.component.html index 0bb8c80..b490c2e 100644 --- a/client/src/app/components/generic-list/generic-list.component.html +++ b/client/src/app/components/list/generic-list/generic-list.component.html @@ -4,17 +4,16 @@
- Filtrer + Rechercher @@ -57,6 +56,7 @@ aria-label="Modifier" > edit + - diff --git a/client/src/app/components/navbar/navbar.component.ts b/client/src/app/components/navbar/main-navbar/main-navbar.component.ts similarity index 72% rename from client/src/app/components/navbar/navbar.component.ts rename to client/src/app/components/navbar/main-navbar/main-navbar.component.ts index d65aa69..fe4e996 100644 --- a/client/src/app/components/navbar/navbar.component.ts +++ b/client/src/app/components/navbar/main-navbar/main-navbar.component.ts @@ -2,12 +2,12 @@ import {Component, inject} from '@angular/core'; import {MatToolbar} from '@angular/material/toolbar'; import {MatButton} from '@angular/material/button'; import {Router, RouterLink} from '@angular/router'; -import {AuthService} from '../../services/auth/auth.service'; +import {AuthService} from '../../../services/auth/auth.service'; import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; import {MatIcon} from '@angular/material/icon'; @Component({ - selector: 'app-navbar', + selector: 'app-main-navbar', standalone: true, imports: [ MatToolbar, @@ -18,22 +18,18 @@ import {MatIcon} from '@angular/material/icon'; MatMenu, MatMenuItem ], - templateUrl: './navbar.component.html', - styleUrl: './navbar.component.css' + templateUrl: './main-navbar.component.html', + styleUrl: './main-navbar.component.css' }) -export class NavbarComponent { +export class MainNavbarComponent { protected readonly authService = inject(AuthService); private readonly router: Router = inject(Router); - login() { - this.router.navigate(['/login'], {queryParams: {redirect: '/profile'}}).then(); - } - logout() { this.authService.logout().subscribe({ next: () => { - this.login(); + this.router.navigate(['/login'], {queryParams: {redirect: '/profile'}}).then(); }, error: (err) => { console.error('Logout failed:', err); diff --git a/client/src/app/components/navbar/navbar.component.spec.ts b/client/src/app/components/navbar/navbar.component.spec.ts deleted file mode 100644 index cfedf9e..0000000 --- a/client/src/app/components/navbar/navbar.component.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { NavbarComponent } from './navbar.component'; - -describe('NavbarComponent', () => { - let component: NavbarComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [NavbarComponent] - }) - .compileComponents(); - - fixture = TestBed.createComponent(NavbarComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/client/src/app/components/platform-list/platform-list.component.html b/client/src/app/components/platform-list/platform-list.component.html deleted file mode 100644 index a6463d1..0000000 --- a/client/src/app/components/platform-list/platform-list.component.html +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/client/src/app/components/product-form/product-form.component.html b/client/src/app/components/product-form/product-form.component.html deleted file mode 100644 index 99b2c89..0000000 --- a/client/src/app/components/product-form/product-form.component.html +++ /dev/null @@ -1 +0,0 @@ -

product-form works!

diff --git a/client/src/app/components/product-form/product-form.component.ts b/client/src/app/components/product-form/product-form.component.ts deleted file mode 100644 index 8d9fa7a..0000000 --- a/client/src/app/components/product-form/product-form.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-product-form', - standalone: true, - imports: [], - templateUrl: './product-form.component.html', - styleUrl: './product-form.component.css' -}) -export class ProductFormComponent { - -} diff --git a/client/src/app/components/products-list/products-list.component.html b/client/src/app/components/products-list/products-list.component.html deleted file mode 100644 index b579034..0000000 --- a/client/src/app/components/products-list/products-list.component.html +++ /dev/null @@ -1,125 +0,0 @@ -
- -
-
- -
-
- - -
- - Rechercher - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Nom{{ product.title }}Description{{ product.description }}Catégorie{{ product.category.name }}Plateforme{{ product.platform.name }}État{{ product.condition.displayName }}Complet - @if (product.complete) { - check_circle - } @else { - cancel - } - Notice - @if (product.manual) { - check_circle - } @else { - cancel - } - Prix{{ product.price | currency:'EUR' }}Quantité{{ product.quantity }}Actions - - -
-
- - -
- - -
- - @if (!products || products.length === 0) { -
Aucun produit trouvé.
- } -
diff --git a/client/src/app/components/products-list/products-list.component.ts b/client/src/app/components/products-list/products-list.component.ts deleted file mode 100644 index 95499ac..0000000 --- a/client/src/app/components/products-list/products-list.component.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { - Component, - Input, - Output, - EventEmitter, - ViewChild, - AfterViewInit, - OnChanges, - SimpleChanges, - OnInit, - inject -} from '@angular/core'; -import { - MatCell, MatCellDef, MatColumnDef, MatHeaderCell, - MatHeaderCellDef, MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef, MatTable, - MatTableDataSource -} from '@angular/material/table'; -import {MatPaginator} from '@angular/material/paginator'; -import {MatSort} from '@angular/material/sort'; -import {Product} from '../../interfaces/product'; -import {ProductService} from '../../services/app/product.service'; -import {MatDialog} from '@angular/material/dialog'; -import {MatButton, MatIconButton} from '@angular/material/button'; -import {MatFormField, MatLabel} from '@angular/material/form-field'; -import {MatIcon} from '@angular/material/icon'; -import {MatInput} from '@angular/material/input'; -import {CurrencyPipe} from '@angular/common'; - -@Component({ - selector: 'app-products-list', - templateUrl: './products-list.component.html', - standalone: true, - imports: [ - MatButton, - MatCell, - MatCellDef, - MatColumnDef, - MatFormField, - MatHeaderCell, - MatHeaderRow, - MatHeaderRowDef, - MatIcon, - MatIconButton, - MatInput, - MatPaginator, - MatRow, - MatRowDef, - MatSort, - MatTable, - MatHeaderCellDef, - CurrencyPipe, - MatLabel - ], - styleUrls: ['./products-list.component.css'] -}) -export class ProductsListComponent implements OnInit, AfterViewInit, OnChanges { - - @Input() products: Product[] = []; - @Output() add = new EventEmitter(); - @Output() edit = new EventEmitter(); - @Output() delete = new EventEmitter(); - - displayedColumns: string[] = ['title', 'description', 'category', 'platform', 'condition', 'complete', 'manual', 'price', 'quantity', 'actions']; - dataSource = new MatTableDataSource([]); - - @ViewChild(MatPaginator) paginator!: MatPaginator; - @ViewChild(MatSort) sort!: MatSort; - - private readonly productService: ProductService = inject(ProductService); - private readonly dialog = inject(MatDialog); - - ngOnInit(): void { - if (!this.products || this.products.length === 0) { - this.loadProducts(); - } else { - this.dataSource.data = this.products; - } - } - - ngOnChanges(changes: SimpleChanges): void { - if (changes['products']) { - this.dataSource.data = this.products || []; - } - } - - ngAfterViewInit(): void { - this.dataSource.paginator = this.paginator; - this.dataSource.sort = this.sort; - } - - loadProducts() { - this.productService.getProducts().subscribe({ - next: (products: Product[]) => { - this.products = products || [] - this.dataSource.data = this.products; - console.log("Fetched products:", this.products); - }, - error: () => this.products = [] - }); - } - - onAdd(): void { - - } - - onEdit(product: Product): void { - - } - - onDelete(product: Product): void { - this.delete.emit(product); - this.productService.deleteProduct((product as any).id).subscribe(() => this.loadProducts()); - } - - applyFilter(value: string): void { - this.dataSource.filter = (value || '').trim().toLowerCase(); - } -} diff --git a/client/src/app/pages/add-product/add-product.component.css b/client/src/app/pages/add-product/add-product.component.css deleted file mode 100644 index 552673e..0000000 --- a/client/src/app/pages/add-product/add-product.component.css +++ /dev/null @@ -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; -} diff --git a/client/src/app/pages/add-product/add-product.component.html b/client/src/app/pages/add-product/add-product.component.html deleted file mode 100644 index 80f7073..0000000 --- a/client/src/app/pages/add-product/add-product.component.html +++ /dev/null @@ -1,146 +0,0 @@ -
- - - Ajouter un produit - - - -
- - - - Titre - - @if (isFieldInvalid('title')) { - {{ getFieldError('title') }} - } - - - - - Description - - @if (isFieldInvalid('description')) { - {{ getFieldError('description') }} - } - - - - - Catégorie - - @for (category of categories; track category.id) { - {{ category.name }} - } - - - - - - État - - @for (condition of conditions; track condition.id) { - {{ condition.displayName }} - } - - - - - - Marque - - @for (brand of filteredBrands; track brand.id) { - {{ brand.name }} - } - - - - - - Plateforme - - @for (platform of filteredPlatforms; track platform.id) { - {{ platform.name }} - } - - - - - - Complet - - @if (isFieldInvalid('complete')) { -
{{ getFieldError('complete') }}
- } - - - - Avec notice - - @if (isFieldInvalid('manual')) { -
{{ getFieldError('manual') }}
- } - - - - Prix TTC - - @if (isFieldInvalid('price')) { - {{ getFieldError('price') }} - } - - - - - Quantité - - @if (isFieldInvalid('quantity')) { - {{ getFieldError('quantity') }} - } - - - -
- -
-
-
- - - - - - Voir la liste des produits - - -
-
diff --git a/client/src/app/pages/add-product/add-product.component.ts b/client/src/app/pages/add-product/add-product.component.ts deleted file mode 100644 index 694fa28..0000000 --- a/client/src/app/pages/add-product/add-product.component.ts +++ /dev/null @@ -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>(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); - }; -} diff --git a/client/src/app/pages/admin/admin.component.ts b/client/src/app/pages/admin/admin.component.ts index 8d59fcd..a8cf236 100644 --- a/client/src/app/pages/admin/admin.component.ts +++ b/client/src/app/pages/admin/admin.component.ts @@ -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', diff --git a/client/src/app/pages/home/home.component.html b/client/src/app/pages/home/home.component.html index aecd790..05fb07c 100644 --- a/client/src/app/pages/home/home.component.html +++ b/client/src/app/pages/home/home.component.html @@ -3,8 +3,10 @@

Bonjour, {{ user.firstName }}!

Que souhaitez-vous faire ?


- - +
+ + +
} @else {

Gestion des produits

diff --git a/client/src/app/pages/home/home.component.spec.ts b/client/src/app/pages/home/home.component.spec.ts deleted file mode 100644 index 1191557..0000000 --- a/client/src/app/pages/home/home.component.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HomeComponent } from './home.component'; - -describe('HomeComponent', () => { - let component: HomeComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [HomeComponent] - }) - .compileComponents(); - - fixture = TestBed.createComponent(HomeComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/client/src/app/pages/home/home.component.ts b/client/src/app/pages/home/home.component.ts index 17b64bf..69c31a4 100644 --- a/client/src/app/pages/home/home.component.ts +++ b/client/src/app/pages/home/home.component.ts @@ -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(); diff --git a/client/src/app/pages/login/login.component.spec.ts b/client/src/app/pages/login/login.component.spec.ts deleted file mode 100644 index 18f3685..0000000 --- a/client/src/app/pages/login/login.component.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { LoginComponent } from './login.component'; - -describe('LoginComponent', () => { - let component: LoginComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [LoginComponent] - }) - .compileComponents(); - - fixture = TestBed.createComponent(LoginComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/client/src/app/pages/login/login.component.ts b/client/src/app/pages/login/login.component.ts index 847f8e2..664a266 100644 --- a/client/src/app/pages/login/login.component.ts +++ b/client/src/app/pages/login/login.component.ts @@ -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; } }); diff --git a/client/src/app/pages/not-found/not-found.component.spec.ts b/client/src/app/pages/not-found/not-found.component.spec.ts deleted file mode 100644 index 5b65d9e..0000000 --- a/client/src/app/pages/not-found/not-found.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [NotFoundComponent] - }) - .compileComponents(); - - fixture = TestBed.createComponent(NotFoundComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/client/src/app/pages/products/products.component.html b/client/src/app/pages/products/products.component.html index ff56460..9394c6a 100644 --- a/client/src/app/pages/products/products.component.html +++ b/client/src/app/pages/products/products.component.html @@ -1 +1,7 @@ - + + @if (showList) { + + } + + + diff --git a/client/src/app/pages/products/products.component.ts b/client/src/app/pages/products/products.component.ts index d2cf933..b7ad3fb 100644 --- a/client/src/app/pages/products/products.component.ts +++ b/client/src/app/pages/products/products.component.ts @@ -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(); + } } diff --git a/client/src/app/pages/profile/profile.component.html b/client/src/app/pages/profile/profile.component.html index b496f2c..20f1df4 100644 --- a/client/src/app/pages/profile/profile.component.html +++ b/client/src/app/pages/profile/profile.component.html @@ -5,7 +5,11 @@ account_circle
{{ user.firstName }} {{ user.lastName }} - {{ user.username }} ({{ user.role }}) + @if (user.role == "Administrator") { + {{ user.username }} ({{ user.role }}) + } @else { + {{ user.username }} + }

diff --git a/client/src/app/pages/profile/profile.component.spec.ts b/client/src/app/pages/profile/profile.component.spec.ts deleted file mode 100644 index 17789ee..0000000 --- a/client/src/app/pages/profile/profile.component.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ProfileComponent } from './profile.component'; - -describe('ProfileComponent', () => { - let component: ProfileComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ProfileComponent] - }) - .compileComponents(); - - fixture = TestBed.createComponent(ProfileComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/client/src/app/services/app/condition.service.ts b/client/src/app/services/app/condition.service.ts index f4eaa3b..9c269fd 100644 --- a/client/src/app/services/app/condition.service.ts +++ b/client/src/app/services/app/condition.service.ts @@ -1,31 +1,32 @@ import {inject, Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; +import {Observable} from 'rxjs'; import {Condition} from '../../interfaces/condition'; +import {CrudService} from '../crud.service'; @Injectable({ providedIn: 'root' }) -export class ConditionService { - +export class ConditionService implements CrudService { private readonly http = inject(HttpClient); private readonly BASE_URL = 'http://localhost:3000/api/app/conditions'; - getConditions() { + getAll(): Observable { return this.http.get(this.BASE_URL, {withCredentials: true}); } - addCondition(condition: Condition) { - console.log("Adding condition:", condition); - return this.http.post(this.BASE_URL, condition, {withCredentials: true}); + add(item: Condition): Observable { + console.log('Adding condition:', item); + return this.http.post(this.BASE_URL, item, {withCredentials: true}); } - updateCondition(id: string, condition: Condition) { - console.log("Updating condition:", id, condition); - return this.http.put(`${this.BASE_URL}/${id}`, condition, {withCredentials: true}); + update(id: string | number, item: Condition): Observable { + console.log('Updating condition:', id, item); + return this.http.put(`${this.BASE_URL}/${id}`, item, {withCredentials: true}); } - deleteCondition(id: string) { - console.log("Deleting condition:", id); - return this.http.delete(`${this.BASE_URL}/${id}`, {withCredentials: true}); + delete(id: string | number): Observable { + console.log('Deleting condition:', id); + return this.http.delete(`${this.BASE_URL}/${id}`, {withCredentials: true}); } } diff --git a/client/src/app/services/app/product.service.ts b/client/src/app/services/app/product.service.ts index 56f64ea..afc48c2 100644 --- a/client/src/app/services/app/product.service.ts +++ b/client/src/app/services/app/product.service.ts @@ -1,31 +1,32 @@ import {inject, Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; +import {Observable} from 'rxjs'; import {Product} from '../../interfaces/product'; +import {CrudService} from '../crud.service'; @Injectable({ providedIn: 'root' }) -export class ProductService { - +export class ProductService implements CrudService { private readonly http = inject(HttpClient); private readonly BASE_URL = 'http://localhost:3000/api/app/products'; - getProducts() { + getAll(): Observable { return this.http.get(this.BASE_URL, {withCredentials: true}); } - addProduct(product: Product) { - console.log("Adding product:", product); - return this.http.post(this.BASE_URL, product, {withCredentials: true}); + add(item: Product): Observable { + console.log('Adding product:', item); + return this.http.post(this.BASE_URL, item, {withCredentials: true}); } - updateProduct(id: string, product: Product) { - console.log("Updating product:", id, product); - return this.http.put(`${this.BASE_URL}/${id}`, product, {withCredentials: true}); + update(id: string | number, item: Product): Observable { + console.log('Updating product:', id, item); + return this.http.put(`${this.BASE_URL}/${id}`, item, {withCredentials: true}); } - deleteProduct(id: string) { - console.log("Deleting product:", id); - return this.http.delete(`${this.BASE_URL}/${id}`, {withCredentials: true}); + delete(id: string | number): Observable { + console.log('Deleting product:', id); + return this.http.delete(`${this.BASE_URL}/${id}`, {withCredentials: true}); } } diff --git a/client/src/app/services/user/user.service.spec.ts b/client/src/app/services/user/user.service.spec.ts deleted file mode 100644 index 3f804c9..0000000 --- a/client/src/app/services/user/user.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { UserService } from './user.service'; - -describe('UserService', () => { - let service: UserService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(UserService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/client/src/app/services/user/user.service.ts b/client/src/app/services/user/user.service.ts deleted file mode 100644 index 3569db9..0000000 --- a/client/src/app/services/user/user.service.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class UserService { - - constructor() { } -}