Compare commits

...

13 Commits

Author SHA1 Message Date
sanchezvem 675ca4ea09 Merge remote-tracking branch 'origin/develop' 2026-06-08 12:26:10 +01:00
sanchezvem 47b8765906 Changed method to see settings pictures 2026-06-05 11:55:31 +01:00
sanchezvem 3c8d8c5825 Merge branch 'develop' 2026-06-01 11:10:58 +01:00
sanchezvem 09763ea730 Added password rules 2026-06-01 11:07:43 +01:00
sanchezvem e29de8e167 deleted unused import 2026-06-01 10:42:55 +01:00
sanchezvem 80b4726004 Added conditions to check role after connexion and changed guards 2026-06-01 10:41:50 +01:00
Cristiano cf53e4c8ef Merge remote-tracking branch 'origin/develop' into develop 2026-05-30 15:00:14 +02:00
Cristiano 9b898432c0 Mask user for employee on navbar 2026-05-29 14:17:45 +02:00
Cristiano d0e98482b9 Added guards for auth and role 2026-05-29 14:07:42 +02:00
sanchezvem 39a831b99b revert dcaf85a316
revert first commit of the day
2025-11-20 14:31:18 +01:00
sanchezvem 0d26ac2457 fix audit error 2025-11-20 14:20:33 +01:00
sanchezvem dcaf85a316 first commit of the day 2025-11-17 10:19:47 +01:00
sanchezvem df651fd052 first commit 2025-11-15 13:23:51 +01:00
24 changed files with 188 additions and 66 deletions
+10
View File
@@ -18,6 +18,7 @@
"@tailwindcss/postcss": "^4.1.17", "@tailwindcss/postcss": "^4.1.17",
"@tailwindcss/vite": "^4.1.17", "@tailwindcss/vite": "^4.1.17",
"browser-image-compression": "^2.0.2", "browser-image-compression": "^2.0.2",
"jwt-decode": "^4.0.0",
"ng-zorro-antd": "^20.4.0", "ng-zorro-antd": "^20.4.0",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"rimraf": "^6.1.3", "rimraf": "^6.1.3",
@@ -6912,6 +6913,15 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/jwt-decode": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
"integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/less": { "node_modules/less": {
"version": "4.4.2", "version": "4.4.2",
"resolved": "https://registry.npmjs.org/less/-/less-4.4.2.tgz", "resolved": "https://registry.npmjs.org/less/-/less-4.4.2.tgz",
+1
View File
@@ -32,6 +32,7 @@
"@tailwindcss/postcss": "^4.1.17", "@tailwindcss/postcss": "^4.1.17",
"@tailwindcss/vite": "^4.1.17", "@tailwindcss/vite": "^4.1.17",
"browser-image-compression": "^2.0.2", "browser-image-compression": "^2.0.2",
"jwt-decode": "^4.0.0",
"ng-zorro-antd": "^20.4.0", "ng-zorro-antd": "^20.4.0",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"rimraf": "^6.1.3", "rimraf": "^6.1.3",
+17 -8
View File
@@ -1,4 +1,5 @@
import {Routes} from '@angular/router'; import {Routes} from '@angular/router';
import {authGuard} from "./guards/auth.guard";
export const routes: Routes = [ export const routes: Routes = [
{ {
@@ -22,35 +23,43 @@ export const routes: Routes = [
}, },
{ {
path: 'dashboard', path: 'dashboard',
loadComponent: () => import('./pages/dashboard/dashboard').then(m => m.Dashboard) loadComponent: () => import('./pages/dashboard/dashboard').then(m => m.Dashboard),
canActivate: [authGuard]
}, },
{ {
path: 'stock', path: 'stock',
loadComponent: () => import('./pages/stock/stock').then(m => m.Stock) loadComponent: () => import('./pages/stock/stock').then(m => m.Stock),
canActivate: [authGuard]
}, },
{ {
path: 'supplier', path: 'supplier',
loadComponent: () => import('./pages/supplier/supplier').then(m => m.Supplier) loadComponent: () => import('./pages/supplier/supplier').then(m => m.Supplier),
canActivate: [authGuard]
}, },
{ {
path: 'deliverer', path: 'deliverer',
loadComponent: () => import('./pages/deliverer/deliverer').then(m => m.Deliverer) loadComponent: () => import('./pages/deliverer/deliverer').then(m => m.Deliverer),
canActivate: [authGuard]
}, },
{ {
path: 'quotation', path: 'quotation',
loadComponent: () => import('./pages/quotation/quotation').then(m => m.Quotation) loadComponent: () => import('./pages/quotation/quotation').then(m => m.Quotation),
canActivate: [authGuard]
}, },
{ {
path: 'purchase-order', path: 'purchase-order',
loadComponent: () => import('./pages/purchase-order/purchase-order').then(m => m.PurchaseOrder) loadComponent: () => import('./pages/purchase-order/purchase-order').then(m => m.PurchaseOrder),
canActivate: [authGuard]
}, },
{ {
path: 'delivery-note', path: 'delivery-note',
loadComponent: () => import('./pages/delivery-note/delivery-note').then(m => m.DeliveryNote) loadComponent: () => import('./pages/delivery-note/delivery-note').then(m => m.DeliveryNote),
canActivate: [authGuard]
}, },
{ {
path: 'user', path: 'user',
loadComponent: () => import('./pages/user/user').then(m => m.User) loadComponent: () => import('./pages/user/user').then(m => m.User),
canActivate: [authGuard],
}, },
{ {
path: '**', path: '**',
@@ -43,9 +43,11 @@
<div style="justify-content: center; display: flex"> <div style="justify-content: center; display: flex">
<nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer" <nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer"
(click)="openEditModal(deliverer)"></nz-icon> (click)="openEditModal(deliverer)"></nz-icon>
<nz-divider nzType="vertical"></nz-divider> @if (admin()){
<nz-icon nzType="delete" nzTheme="outline" (click)="delete(deliverer.id)" <nz-divider nzType="vertical"></nz-divider>
class="text-red-600 cursor-pointer"></nz-icon> <nz-icon nzType="delete" nzTheme="outline" (click)="delete(deliverer.id)"
class="text-red-600 cursor-pointer"></nz-icon>
}
</div> </div>
</td> </td>
</tr> </tr>
@@ -9,6 +9,7 @@ import {DelivererForm} from "../deliverer-form/deliverer-form";
import {DeliverersService, GetDelivererDto, GetSupplierDto} from "../../services/api"; import {DeliverersService, GetDelivererDto, GetSupplierDto} from "../../services/api";
import {NzNotificationService} from "ng-zorro-antd/notification"; import {NzNotificationService} from "ng-zorro-antd/notification";
import {firstValueFrom} from "rxjs"; import {firstValueFrom} from "rxjs";
import {AuthService} from "../../services/auth.service";
@Component({ @Component({
selector: 'app-deliverer-table', selector: 'app-deliverer-table',
@@ -28,14 +29,17 @@ import {firstValueFrom} from "rxjs";
export class DelivererTable implements OnInit { export class DelivererTable implements OnInit {
private deliverersService = inject(DeliverersService); private deliverersService = inject(DeliverersService);
private notificationService = inject(NzNotificationService) private notificationService = inject(NzNotificationService)
private authService = inject(AuthService);
deliverers = signal<GetDelivererDto[]>([]); deliverers = signal<GetDelivererDto[]>([]);
deliverersLoading = signal<boolean>(false); deliverersLoading = signal<boolean>(false);
admin = signal<boolean>(false);
modal = viewChild.required<ModalNav>('modalNav'); modal = viewChild.required<ModalNav>('modalNav');
async ngOnInit() { async ngOnInit() {
await this.fetchDeliverers(); await this.fetchDeliverers();
this.admin.set(this.authService.isAdmin());
} }
async fetchDeliverers() { async fetchDeliverers() {
@@ -38,9 +38,11 @@
<nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer" <nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer"
(click)="openEditModal(deliveryNote)"></nz-icon> (click)="openEditModal(deliveryNote)"></nz-icon>
<nz-divider nzType="vertical"></nz-divider> <nz-divider nzType="vertical"></nz-divider>
<nz-icon nzType="delete" nzTheme="outline" (click)="delete(deliveryNote.id)" @if (admin()){
class="cursor-pointer text-red-700"/> <nz-icon nzType="delete" nzTheme="outline" (click)="delete(deliveryNote.id)"
<nz-divider nzType="vertical"></nz-divider> class="cursor-pointer text-red-700"/>
<nz-divider nzType="vertical"></nz-divider>
}
<nz-icon nzType="export" nzTheme="outline" (click)="export(deliveryNote.id)" <nz-icon nzType="export" nzTheme="outline" (click)="export(deliveryNote.id)"
class="cursor-pointer text-green-700"/> class="cursor-pointer text-green-700"/>
</div> </div>
@@ -10,6 +10,7 @@ import {NzNotificationService} from "ng-zorro-antd/notification";
import {firstValueFrom} from "rxjs"; import {firstValueFrom} from "rxjs";
import {format} from "date-fns"; import {format} from "date-fns";
import {FileService} from "../../services/file.service"; import {FileService} from "../../services/file.service";
import {AuthService} from "../../services/auth.service";
@Component({ @Component({
selector: 'app-deliverery-note-table', selector: 'app-deliverery-note-table',
@@ -28,9 +29,11 @@ export class DelivereryNoteTable implements OnInit {
private deliveryNotesService = inject(DeliverynotesService); private deliveryNotesService = inject(DeliverynotesService);
private notificationService = inject(NzNotificationService); private notificationService = inject(NzNotificationService);
private fileService = inject(FileService); private fileService = inject(FileService);
private authService = inject(AuthService);
deliveryNotes = signal<GetDeliveryNoteDto[]>([]); deliveryNotes = signal<GetDeliveryNoteDto[]>([]);
deliveryNotesLoading = signal<boolean>(false); deliveryNotesLoading = signal<boolean>(false);
admin = signal<boolean>(false);
modal = viewChild.required<ModalNav>('modalNav'); modal = viewChild.required<ModalNav>('modalNav');
@@ -38,6 +41,7 @@ export class DelivereryNoteTable implements OnInit {
async ngOnInit() { async ngOnInit() {
await this.fetchDeliveryNotes(); await this.fetchDeliveryNotes();
this.admin.set(this.authService.isAdmin());
} }
async fetchDeliveryNotes() { async fetchDeliveryNotes() {
+8 -6
View File
@@ -59,12 +59,14 @@
</li> </li>
</ul> </ul>
</li> </li>
<li nz-menu-item routerLinkActive="ant-menu-item-selected"> @if (admin()) {
<a routerLink="/user"> <li nz-menu-item routerLinkActive="ant-menu-item-selected">
<nz-icon nzType="user"></nz-icon> <a routerLink="/user">
<span>Utilisateur</span> <nz-icon nzType="user"></nz-icon>
</a> <span>Utilisateur</span>
</li> </a>
</li>
}
</ul> </ul>
<!-- ICONES À DROITE --> <!-- ICONES À DROITE -->
+8 -2
View File
@@ -1,4 +1,4 @@
import {Component, inject} from '@angular/core'; import {Component, inject, OnInit, signal} from '@angular/core';
import {ModalNav} from "../modal-nav/modal-nav"; import {ModalNav} from "../modal-nav/modal-nav";
import {NzContentComponent, NzHeaderComponent, NzLayoutComponent} from "ng-zorro-antd/layout"; import {NzContentComponent, NzHeaderComponent, NzLayoutComponent} from "ng-zorro-antd/layout";
import {NzIconDirective} from "ng-zorro-antd/icon"; import {NzIconDirective} from "ng-zorro-antd/icon";
@@ -28,10 +28,16 @@ import {AuthService} from "../../services/auth.service";
templateUrl: './layout.html', templateUrl: './layout.html',
styleUrl: './layout.css', styleUrl: './layout.css',
}) })
export class Layout { export class Layout implements OnInit {
private authService = inject(AuthService); private authService = inject(AuthService);
private router = inject(Router); private router = inject(Router);
admin = signal<boolean>(false);
ngOnInit() {
this.admin.set(this.authService.isAdmin());
}
async disconnect() { async disconnect() {
this.authService.logout(); this.authService.logout();
await this.router.navigate(['/login']); await this.router.navigate(['/login']);
@@ -60,9 +60,11 @@
<nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer" <nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer"
(click)="openEditModal(purchaseOrder)"></nz-icon> (click)="openEditModal(purchaseOrder)"></nz-icon>
<nz-divider nzType="vertical"></nz-divider> <nz-divider nzType="vertical"></nz-divider>
<nz-icon nzType="delete" nzTheme="outline" (click)="delete(purchaseOrder.id)" @if (admin()) {
class="cursor-pointer text-red-700"/> <nz-icon nzType="delete" nzTheme="outline" (click)="delete(purchaseOrder.id)"
<nz-divider nzType="vertical"></nz-divider> class="cursor-pointer text-red-700"/>
<nz-divider nzType="vertical"></nz-divider>
}
<nz-icon nzType="export" nzTheme="outline" (click)="export(purchaseOrder.id)" <nz-icon nzType="export" nzTheme="outline" (click)="export(purchaseOrder.id)"
class="cursor-pointer text-green-700"/> class="cursor-pointer text-green-700"/>
<nz-divider nzType="vertical"></nz-divider> <nz-divider nzType="vertical"></nz-divider>
@@ -17,6 +17,7 @@ import {firstValueFrom} from "rxjs";
import {FileService} from "../../services/file.service"; import {FileService} from "../../services/file.service";
import {QuantityForm} from "../quantity-form/quantity-form"; import {QuantityForm} from "../quantity-form/quantity-form";
import {DelivererChoice} from "../deliverer-choice/deliverer-choice"; import {DelivererChoice} from "../deliverer-choice/deliverer-choice";
import {AuthService} from "../../services/auth.service";
@Component({ @Component({
selector: 'app-purchase-order-table', selector: 'app-purchase-order-table',
@@ -38,9 +39,11 @@ export class PurchaseOrderTable implements OnInit {
private notificationService = inject(NzNotificationService); private notificationService = inject(NzNotificationService);
private fileService = inject(FileService); private fileService = inject(FileService);
private deliveryNoteService = inject(DeliverynotesService); private deliveryNoteService = inject(DeliverynotesService);
private authService = inject(AuthService);
purchaseOrders = signal<GetPurchaseOrderDto[]>([]); purchaseOrders = signal<GetPurchaseOrderDto[]>([]);
purchaseOrdersLoading = signal<boolean>(false); purchaseOrdersLoading = signal<boolean>(false);
admin = signal<boolean>(false);
modal = viewChild.required<ModalNav>('modalNav'); modal = viewChild.required<ModalNav>('modalNav');
modalQuantity = viewChild.required<ModalNav>('modalQuantity'); modalQuantity = viewChild.required<ModalNav>('modalQuantity');
@@ -48,6 +51,7 @@ export class PurchaseOrderTable implements OnInit {
async ngOnInit() { async ngOnInit() {
await this.fetchPurchaseOrder(); await this.fetchPurchaseOrder();
this.admin.set(this.authService.isAdmin());
} }
async fetchPurchaseOrder() { async fetchPurchaseOrder() {
@@ -60,9 +60,11 @@
<nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer" <nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer"
(click)="openEditModal(quotation)"></nz-icon> (click)="openEditModal(quotation)"></nz-icon>
<nz-divider nzType="vertical"></nz-divider> <nz-divider nzType="vertical"></nz-divider>
<nz-icon nzType="delete" nzTheme="outline" class="cursor-pointer text-red-700" @if (admin()) {
(click)="delete(quotation.id)"/> <nz-icon nzType="delete" nzTheme="outline" class="cursor-pointer text-red-700"
<nz-divider nzType="vertical"></nz-divider> (click)="delete(quotation.id)"/>
<nz-divider nzType="vertical"></nz-divider>
}
<nz-icon nzType="export" (click)="export(quotation.id)" nzTheme="outline" <nz-icon nzType="export" (click)="export(quotation.id)" nzTheme="outline"
class="cursor-pointer text-green-700"/> class="cursor-pointer text-green-700"/>
</div> </div>
@@ -14,6 +14,7 @@ import {NzNotificationService} from "ng-zorro-antd/notification";
import {firstValueFrom} from "rxjs"; import {firstValueFrom} from "rxjs";
import {FileService} from "../../services/file.service"; import {FileService} from "../../services/file.service";
import {QuantityForm} from "../quantity-form/quantity-form"; import {QuantityForm} from "../quantity-form/quantity-form";
import {AuthService} from "../../services/auth.service";
@Component({ @Component({
selector: 'app-quotation-table', selector: 'app-quotation-table',
@@ -34,15 +35,18 @@ export class QuotationTable implements OnInit {
private quotationsService = inject(QuotationsService); private quotationsService = inject(QuotationsService);
private notificationService = inject(NzNotificationService); private notificationService = inject(NzNotificationService);
private fileService = inject(FileService); private fileService = inject(FileService);
private authService = inject(AuthService);
quotations = signal<GetQuotationDto[]>([]); quotations = signal<GetQuotationDto[]>([]);
quotationsLoading = signal<boolean>(false); quotationsLoading = signal<boolean>(false);
admin = signal<boolean>(false);
modal = viewChild.required<ModalNav>('modalNav'); modal = viewChild.required<ModalNav>('modalNav');
modalQuantity = viewChild.required<ModalNav>('modalQuantity'); modalQuantity = viewChild.required<ModalNav>('modalQuantity');
async ngOnInit() { async ngOnInit() {
await this.fetchQuotations(); await this.fetchQuotations();
this.admin.set(this.authService.isAdmin());
} }
async fetchQuotations() { async fetchQuotations() {
@@ -4,41 +4,57 @@
<div class="row"> <div class="row">
<div class="row-left"> <div class="row-left">
@if (settings().logo) { @if (settings().logo) {
<img [src]="'data:image/jpeg;base64,' + settings().logo" alt=""/> <img [src]="settings().logo" alt=""/>
} @else { } @else {
<img [src]="setting.logo" alt="logo"> <img [src]="setting.logo" alt="logo">
} }
</div> </div>
<div class="row-right"> @if (admin()){
<nz-form-item> <div class="row-right">
<nz-form-label nzSpan="9">Logo</nz-form-label> <nz-form-item>
<nz-form-control nzErrorTip="Ce champ est requis"> <nz-form-label nzSpan="9">Logo</nz-form-label>
<input #fileInputLogo nz-input type="file" placeholder="Déposer" <nz-form-control nzErrorTip="Ce champ est requis">
(change)="onFileChange('logo', fileInputLogo.files)"> <input #fileInputLogo nz-input type="file" placeholder="Déposer"
</nz-form-control> (change)="onFileChange('logo', fileInputLogo.files)">
</nz-form-item> </nz-form-control>
</div> </nz-form-item>
</div>
} @else {
<div class="row-right">
<nz-form-item>
<p class="text-red-600">Vous ne pouvez pas modifier le logo</p>
</nz-form-item>
</div>
}
</div> </div>
<!-- Signature --> <!-- Signature -->
<div class="row"> <div class="row">
<div class="row-left"> <div class="row-left">
@if (settings().electronicSignature) { @if (settings().electronicSignature) {
<img [src]="'data:image/jpeg;base64,' + settings().electronicSignature" alt=""/> <img [src]="settings().electronicSignature" alt=""/>
} @else { } @else {
<img [src]="setting.electronicSignature" alt="logo"> <img [src]="setting.electronicSignature" alt="logo">
} }
</div> </div>
<div class="row-right"> @if (admin()) {
<nz-form-item> <div class="row-right">
<nz-form-label nzSpan="9">Signature</nz-form-label> <nz-form-item>
<nz-form-control nzErrorTip="Ce champ est requis"> <nz-form-label nzSpan="9">Signature</nz-form-label>
<input #fileInputSignature nz-input type="file" placeholder="Déposer" <nz-form-control nzErrorTip="Ce champ est requis">
(change)="onFileChange('electronicSignature', fileInputSignature.files)"> <input #fileInputSignature nz-input type="file" placeholder="Déposer"
</nz-form-control> (change)="onFileChange('electronicSignature', fileInputSignature.files)">
</nz-form-item> </nz-form-control>
</div> </nz-form-item>
</div>
} @else {
<div class="row-right">
<nz-form-item>
<p class="text-red-600">Vous ne pouvez pas modifier la signature</p>
</nz-form-item>
</div>
}
</div> </div>
</form> </form>
@@ -8,6 +8,7 @@ import {firstValueFrom} from "rxjs";
import {GetSettingDto, SettingsService} from "../../services/api"; import {GetSettingDto, SettingsService} from "../../services/api";
import {NzNotificationService} from "ng-zorro-antd/notification"; import {NzNotificationService} from "ng-zorro-antd/notification";
import imageCompression from "browser-image-compression"; import imageCompression from "browser-image-compression";
import {AuthService} from "../../services/auth.service";
@Component({ @Component({
selector: 'app-setting-form', selector: 'app-setting-form',
@@ -27,8 +28,10 @@ import imageCompression from "browser-image-compression";
export class SettingForm implements OnInit { export class SettingForm implements OnInit {
private settingsService = inject(SettingsService); private settingsService = inject(SettingsService);
private notificationService = inject(NzNotificationService); private notificationService = inject(NzNotificationService);
private authService = inject(AuthService);
settings = signal<GetSettingDto>({}); settings = signal<GetSettingDto>({});
admin = signal<boolean>(false);
setting: SettingInfo = { setting: SettingInfo = {
logo: 'https://www.pyro-fetes.com/wp-content/themes/pcptheme/img/logo-pyro-fetes-OR-top.png', logo: 'https://www.pyro-fetes.com/wp-content/themes/pcptheme/img/logo-pyro-fetes-OR-top.png',
@@ -42,6 +45,7 @@ export class SettingForm implements OnInit {
async ngOnInit() { async ngOnInit() {
await this.fetchSettings(); await this.fetchSettings();
this.admin.set(this.authService.isAdmin());
} }
async fetchSettings() { async fetchSettings() {
@@ -46,9 +46,11 @@
<div style="justify-content: center; display: flex"> <div style="justify-content: center; display: flex">
<nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer" <nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer"
(click)="openEditModal(product)"></nz-icon> (click)="openEditModal(product)"></nz-icon>
<nz-divider nzType="vertical"></nz-divider> @if (admin()) {
<nz-icon nzType="delete" nzTheme="outline" (click)="delete(product.id)" <nz-divider nzType="vertical"></nz-divider>
class="text-red-600 cursor-pointer"></nz-icon> <nz-icon nzType="delete" nzTheme="outline" (click)="delete(product.id)"
class="text-red-600 cursor-pointer"></nz-icon>
}
</div> </div>
</td> </td>
</tr> </tr>
@@ -7,8 +7,9 @@ import {NzDividerComponent} from "ng-zorro-antd/divider";
import {FormsModule} from "@angular/forms"; import {FormsModule} from "@angular/forms";
import {GetProductDto, ProductsService, WarehouseproductsService} from "../../services/api"; import {GetProductDto, ProductsService, WarehouseproductsService} from "../../services/api";
import {NzNotificationService} from "ng-zorro-antd/notification"; import {NzNotificationService} from "ng-zorro-antd/notification";
import {first, firstValueFrom} from "rxjs"; import {firstValueFrom} from "rxjs";
import {NzCheckboxComponent} from "ng-zorro-antd/checkbox"; import {NzCheckboxComponent} from "ng-zorro-antd/checkbox";
import {AuthService} from "../../services/auth.service";
interface ProductWithQuantity extends GetProductDto { interface ProductWithQuantity extends GetProductDto {
totalQuantity?: number; totalQuantity?: number;
@@ -34,9 +35,11 @@ export class StockTable implements OnInit {
private productsService = inject(ProductsService); private productsService = inject(ProductsService);
private wareHousseProductsService = inject(WarehouseproductsService) private wareHousseProductsService = inject(WarehouseproductsService)
private notificationService = inject(NzNotificationService) private notificationService = inject(NzNotificationService)
private authService = inject(AuthService);
products = signal<ProductWithQuantity[]>([]); products = signal<ProductWithQuantity[]>([]);
productsLoading = signal<boolean>(false); productsLoading = signal<boolean>(false);
admin = signal<boolean>(false);
modal = viewChild.required<ModalNav>('modalNav'); modal = viewChild.required<ModalNav>('modalNav');
@@ -50,6 +53,7 @@ export class StockTable implements OnInit {
async ngOnInit() { async ngOnInit() {
await this.fetchProducts(); await this.fetchProducts();
this.admin.set(this.authService.isAdmin());
} }
async fetchProducts() { async fetchProducts() {
@@ -46,10 +46,12 @@
<nz-icon nzType="edit" nzTheme="outline" <nz-icon nzType="edit" nzTheme="outline"
class="cursor-pointer text-gray-600 hover:text-gray-900" class="cursor-pointer text-gray-600 hover:text-gray-900"
(click)="openEditProductModal(product, supplier.id)"></nz-icon> (click)="openEditProductModal(product, supplier.id)"></nz-icon>
<nz-divider nzType="vertical"></nz-divider> @if (admin()) {
<nz-icon nzType="delete" nzTheme="outline" <nz-divider nzType="vertical"></nz-divider>
class="cursor-pointer text-red-600 hover:text-red-800" <nz-icon nzType="delete" nzTheme="outline"
(click)="deleteProduct(product.productId, supplier.id)"></nz-icon> class="cursor-pointer text-red-600 hover:text-red-800"
(click)="deleteProduct(product.productId, supplier.id)"></nz-icon>
}
</div> </div>
</td> </td>
</tr> </tr>
@@ -62,9 +64,11 @@
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer" <nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer"
(click)="openEditModal(supplier)"></nz-icon> (click)="openEditModal(supplier)"></nz-icon>
<nz-divider nzType="vertical"></nz-divider> @if (admin()) {
<nz-icon nzType="delete" nzTheme="outline" (click)="delete(supplier.id)" <nz-divider nzType="vertical"></nz-divider>
class="text-red-600 cursor-pointer"></nz-icon> <nz-icon nzType="delete" nzTheme="outline" (click)="delete(supplier.id)"
class="text-red-600 cursor-pointer"></nz-icon>
}
</div> </div>
</td> </td>
</tr> </tr>
@@ -9,6 +9,7 @@ import {GetPriceDto, GetSupplierDto, PricesService, SuppliersService} from "../.
import {NzNotificationService} from "ng-zorro-antd/notification"; import {NzNotificationService} from "ng-zorro-antd/notification";
import {firstValueFrom} from "rxjs"; import {firstValueFrom} from "rxjs";
import {PriceForm} from "../price-form/price-form"; import {PriceForm} from "../price-form/price-form";
import {AuthService} from "../../services/auth.service";
@Component({ @Component({
selector: 'app-supplier-table', selector: 'app-supplier-table',
@@ -29,9 +30,11 @@ export class SupplierTable implements OnInit {
private suppliersService = inject(SuppliersService); private suppliersService = inject(SuppliersService);
private pricesService = inject(PricesService); private pricesService = inject(PricesService);
private notificationService = inject(NzNotificationService); private notificationService = inject(NzNotificationService);
private authService = inject(AuthService);
suppliers = signal<GetSupplierDto[]>([]); suppliers = signal<GetSupplierDto[]>([]);
suppliersLoading = signal<boolean>(false); suppliersLoading = signal<boolean>(false);
admin = signal<boolean>(false);
supplierModal = viewChild.required<ModalNav>('supplierModal'); supplierModal = viewChild.required<ModalNav>('supplierModal');
productModal = viewChild.required<ModalNav>('productModal'); productModal = viewChild.required<ModalNav>('productModal');
@@ -42,6 +45,7 @@ export class SupplierTable implements OnInit {
async ngOnInit() { async ngOnInit() {
await this.fetchSuppliers(); await this.fetchSuppliers();
this.admin.set(this.authService.isAdmin());
} }
async fetchSuppliers() { async fetchSuppliers() {
+14
View File
@@ -0,0 +1,14 @@
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService} from "../services/auth.service";
export const authGuard = async () => {
const auth = inject(AuthService);
const router = inject(Router);
if(!auth.userAuthenticated()) {
await router.navigateByUrl('/login');
return false;
}
return true
};
-5
View File
@@ -1,5 +0,0 @@
export interface UserInfo {
name: string;
email: string;
fonction: string;
}
+10
View File
@@ -7,6 +7,16 @@
size="35%"> size="35%">
<app-profil-form #profilForm></app-profil-form> <app-profil-form #profilForm></app-profil-form>
<div class="text-[12px] text-gray-400 flex justify-center items-center flex-col">
<p>Consignes du mot de passe :</p>
<ul class="ml-10">
<li>12 caractères</li>
<li>Au moins une majuscule</li>
<li>Au moins une minuscule</li>
<li>Au moins un chiffre</li>
<li>Au moins un caractère spécial</li>
</ul>
</div>
</app-modal-button> </app-modal-button>
</div> </div>
+1 -1
View File
@@ -45,7 +45,7 @@ export class User {
this.notificationService.success('Success', 'Utilisateur crée') this.notificationService.success('Success', 'Utilisateur crée')
} catch { } catch {
this.notificationService.error('Erreur', 'Erreur d\'enregistrement') this.notificationService.error('Erreur', 'Email ou mot de passe invalide')
} }
} }
} }
+18 -1
View File
@@ -2,6 +2,7 @@ import {inject, Injectable} from '@angular/core';
import {firstValueFrom} from 'rxjs'; import {firstValueFrom} from 'rxjs';
import {NzNotificationService} from 'ng-zorro-antd/notification'; import {NzNotificationService} from 'ng-zorro-antd/notification';
import {UsersService} from "./api"; import {UsersService} from "./api";
import { jwtDecode } from "jwt-decode" ;
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
@@ -10,12 +11,15 @@ export class AuthService {
private usersService = inject(UsersService); private usersService = inject(UsersService);
private notificationService = inject(NzNotificationService); private notificationService = inject(NzNotificationService);
private isAuthenticated: boolean = false;
async connectUser(name: string, password: string) { async connectUser(name: string, password: string) {
try { try {
const loginDto = {name, password}; const loginDto = {name, password};
const res = await firstValueFrom(this.usersService.connectUserEndpoint(loginDto)); const res = await firstValueFrom(this.usersService.connectUserEndpoint(loginDto));
localStorage.setItem('jwt', res.token); localStorage.setItem('jwt', res.token);
return true; this.isAuthenticated = true;
return this.isAuthenticated;
} catch { } catch {
this.notificationService.error('Erreur', 'Identifiant invalide'); this.notificationService.error('Erreur', 'Identifiant invalide');
return false; return false;
@@ -31,7 +35,20 @@ export class AuthService {
} }
logout() { logout() {
this.isAuthenticated = false;
localStorage.removeItem('jwt'); localStorage.removeItem('jwt');
} }
userAuthenticated() {
return this.isAuthenticated
}
getRole() {
const jwtDecoded = jwtDecode(this.getToken());
return jwtDecoded['role'];
}
isAdmin(){
return this.getRole() === 'Admin';
}
} }