Merge branch 'feature/supplierTable' into develop

This commit is contained in:
2025-11-28 09:52:25 +01:00
8 changed files with 222 additions and 181 deletions

View File

@@ -1,4 +1,4 @@
<form nz-form nzLayout="horizontal" [formGroup]="supplierForm" (ngSubmit)="submitForm()"> <form nz-form nzLayout="horizontal" [formGroup]="supplierForm">
<nz-form-item nz-flex> <nz-form-item nz-flex>
<nz-form-label nzSpan="9" nzRequired> <nz-form-label nzSpan="9" nzRequired>
@@ -36,6 +36,15 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-form-item nz-flex>
<nz-form-label nzSpan="9" nzRequired>
Code Postal
</nz-form-label>
<nz-form-control nzSpan="12" nzErrorTip="Ce champ est requis">
<input nz-input placeholder="Code Postal" formControlName="zipCode">
</nz-form-control>
</nz-form-item>
<nz-form-item nz-flex> <nz-form-item nz-flex>
<nz-form-label nzSpan="9" nzRequired> <nz-form-label nzSpan="9" nzRequired>
Ville Ville
@@ -50,16 +59,7 @@
Délai Moyen Délai Moyen
</nz-form-label> </nz-form-label>
<nz-form-control nzSpan="12" nzErrorTip="Ce champ est requis"> <nz-form-control nzSpan="12" nzErrorTip="Ce champ est requis">
<input nz-input placeholder="Délai Moyen" formControlName="deliveryDelay"> <input nz-input type="number" placeholder="Délai Moyen" formControlName="deliveryDelay">
</nz-form-control>
</nz-form-item>
<nz-form-item nz-flex>
<nz-form-label nzSpan="9" nzRequired>
Produits
</nz-form-label>
<nz-form-control nzSpan="12" nzErrorTip="Ce champ est requis">
<input nz-input placeholder="Produits" formControlName="product">
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>

View File

@@ -1,9 +1,10 @@
import { Component } from '@angular/core'; import {Component, effect, input} from '@angular/core';
import {NzColDirective} from "ng-zorro-antd/grid"; import {NzColDirective} from "ng-zorro-antd/grid";
import {NzFlexDirective} from "ng-zorro-antd/flex"; import {NzFlexDirective} from "ng-zorro-antd/flex";
import {NzFormControlComponent, NzFormDirective, NzFormItemComponent, NzFormLabelComponent} from "ng-zorro-antd/form"; import {NzFormControlComponent, NzFormDirective, NzFormItemComponent, NzFormLabelComponent} from "ng-zorro-antd/form";
import {NzInputDirective} from "ng-zorro-antd/input"; import {NzInputDirective} from "ng-zorro-antd/input";
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms"; import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
import {GetSupplierDto} from "../../services/api";
@Component({ @Component({
selector: 'app-supplier-form', selector: 'app-supplier-form',
@@ -26,20 +27,26 @@ export class SupplierForm {
email: new FormControl<string>(null, [Validators.required]), email: new FormControl<string>(null, [Validators.required]),
phone: new FormControl<string>(null, [Validators.required]), phone: new FormControl<string>(null, [Validators.required]),
address: new FormControl<string>(null, [Validators.required]), address: new FormControl<string>(null, [Validators.required]),
zipCode: new FormControl<string>(null, [Validators.required]),
city: new FormControl<string>(null, [Validators.required]), city: new FormControl<string>(null, [Validators.required]),
deliveryDelay: new FormControl<string>(null, [Validators.required]), deliveryDelay: new FormControl<string>(null, [Validators.required]),
product: new FormControl<string>(null, [Validators.required]),
}) })
submitForm() { supplier= input<GetSupplierDto>();
// Pour annuler si le formulaire est invalide constructor() {
if (this.supplierForm.invalid) return; effect(() => {
if (this.supplier()) {
// Pour obtenir la valeur du formulaire this.supplierForm.patchValue({
console.log(this.supplierForm.getRawValue()) name: this.supplier().name,
email: this.supplier().email,
// Pour vider le formulaire phone: this.supplier().phone,
this.supplierForm.reset() address: this.supplier().address,
zipCode: this.supplier().zipCode,
city: this.supplier().city,
deliveryDelay: this.supplier().deliveryDelay,
});
}
});
} }
} }

View File

@@ -1,61 +1,66 @@
<nz-table #basicTable [nzData]="listOfSupplier"> <nz-table [nzData]="suppliers()"
[nzLoading]="suppliersLoading()"
[nzFrontPagination]="false">
<thead> <thead>
<tr class="text-center"> <tr style="text-align: center">
<th>Nom</th> <th>Nom</th>
<th>email</th>
<th>Téléphone</th> <th>Téléphone</th>
<th>Email</th>
<th>Adresse</th> <th>Adresse</th>
<th>Code Postal</th>
<th>Ville</th> <th>Ville</th>
<th>Délai Moyen</th> <th>Délai moyen</th>
<th>Produits</th> <th>Produits</th>
<th>Action</th> <th style="display: flex; align-items: center;">Action</th>
</tr> </tr>
</thead> </thead>
<tbody class="text-center"> <tbody style="text-align: center">
@for (data of basicTable.data; track data) { @for (supplier of suppliers(); track supplier.id) {
<tr> <tr>
<td>{{data.name}}</td> <td>{{ supplier.name }}</td>
<td>{{data.email}}</td> <td>{{ supplier.phone }}</td>
<td>{{data.phone}}</td> <td>{{ supplier.email }}</td>
<td>{{data.address}}, {{data.zipCode}}</td> <td>{{ supplier.address}}</td>
<td>{{data.city}}</td> <td>{{ supplier.zipCode}}</td>
<td>{{data.deliveryDelay}}</td> <td>{{ supplier.city}}</td>
<td>{{ supplier.deliveryDelay}} jours</td>
<td> <td>
<app-modal-button type="link" name="Voir les produits"> <app-modal-button type="link" [name]="'Voir les produits'">
<div style="max-height: 400px; overflow-y: auto;"> <nz-table [nzData]="supplier.products" [nzFrontPagination]="false">
<nz-table [nzData]="data.products">
<thead> <thead>
<tr class="text-center"> <tr style="text-align: center">
<th>Produits</th>
<th>Nom</th> <th>Nom</th>
<th>Référence</th> <th>Référence</th>
<th>Prix</th> <th>Prix</th>
</tr> </tr>
</thead> </thead>
<tbody class="text-center"> <tbody style="text-align: center">
@for (product of data.products; track product) { @for (product of supplier.products; track product.id) {
<tr> <tr>
<td>{{ product.name }}</td> <td>{{ product.name }}</td>
<td>{{product.reference}}</td> <td>{{ product.references }}</td>
<td>xx.x€</td> <td>Price ???</td>
</tr> </tr>
} }
</tbody> </tbody>
</nz-table> </nz-table>
</div>
</app-modal-button> </app-modal-button>
</td> </td>
<td> <td>
<div style="justify-content: center; display: flex"> <div style="display: flex; align-items: center;">
<app-modal-nav nameIcon="edit" name="Modification du fournisseur" class="cursor-pointer"> <nz-icon nzType="edit" nzTheme="outline" class="cursor-pointer" (click)="openEditModal(supplier)"></nz-icon>
<app-supplier-form></app-supplier-form>
</app-modal-nav>
<nz-divider nzType="vertical"></nz-divider> <nz-divider nzType="vertical"></nz-divider>
<div> <nz-icon nzType="delete" nzTheme="outline" (click)="delete(supplier.id)" class="text-red-600 cursor-pointer"></nz-icon>
<nz-icon nzType="delete" nzTheme="outline" class="cursor-pointer text-red-700"/>
</div>
</div> </div>
</td> </td>
</tr> </tr>
} }
</tbody> </tbody>
</nz-table> </nz-table>
<div class="hidden">
<app-modal-nav #modalNav nameIcon="edit" [name]="'Modifier'" (ok)="onModalOk(selectedSupplier.id, supplierForm, modalNav)" (cancel)="onModalCancel(modalNav)">
<app-supplier-form #supplierForm [supplier]="selectedSupplier"></app-supplier-form>
</app-modal-nav>
</div>

View File

@@ -1,13 +1,13 @@
import { Component } from '@angular/core'; import {Component, inject, OnInit, signal, viewChild} from '@angular/core';
import {ModalNav} from "../modal-nav/modal-nav"; import {ModalNav} from "../modal-nav/modal-nav";
import {NzDividerComponent} from "ng-zorro-antd/divider"; import {NzDividerComponent} from "ng-zorro-antd/divider";
import {NzIconDirective} from "ng-zorro-antd/icon"; import {NzIconDirective} from "ng-zorro-antd/icon";
import {NzTableComponent} from "ng-zorro-antd/table"; import {NzTableComponent} from "ng-zorro-antd/table";
import {ModalButton} from "../modal-button/modal-button"; import {ModalButton} from "../modal-button/modal-button";
import {DatePipe} from "@angular/common";
import {SupplierForm} from "../supplier-form/supplier-form"; import {SupplierForm} from "../supplier-form/supplier-form";
import {SupplierInfo} from "../../interfaces/supplier.interface"; import {GetSupplierDto, SuppliersService} from "../../services/api";
import {DelivererForm} from "../deliverer-form/deliverer-form"; import {NzNotificationService} from "ng-zorro-antd/notification";
import {firstValueFrom} from "rxjs";
@Component({ @Component({
selector: 'app-supplier-table', selector: 'app-supplier-table',
@@ -23,112 +23,92 @@ import {DelivererForm} from "../deliverer-form/deliverer-form";
styleUrl: './supplier-table.css', styleUrl: './supplier-table.css',
}) })
export class SupplierTable { export class SupplierTable implements OnInit {
listOfSupplier: SupplierInfo[] = [ private suppliersService = inject(SuppliersService);
{ private notificationService = inject(NzNotificationService)
name: "PyroNova", suppliers = signal<GetSupplierDto[]>([]);
email: "contact@pyronova.com", suppliersLoading = signal<boolean>(false);
phone: "+33 1 45 23 67 89", updateSupplier = viewChild.required<SupplierForm>('supplierForm');
address: "12 Rue des Artisans", modal = viewChild.required<ModalNav>('modalNav');
zipCode: "69003",
city: "Lyon",
deliveryDelay: 4,
products: []
},
{
name: "FX Industries",
email: "sales@fxindus.com",
phone: "+33 2 41 22 90 10",
address: "118 Avenue Lumière",
zipCode: "49000",
city: "Angers",
deliveryDelay: 6,
products: []
},
{
name: "EuroFire",
email: "info@eurofire.eu",
phone: "+33 1 80 22 11 77",
address: "2 Avenue de lEurope",
zipCode: "75012",
city: "Paris",
deliveryDelay: 3,
products: []
},
{
name: "FlashEffect",
email: "contact@flasheffect.fr",
phone: "+33 4 72 81 91 22",
address: "44 Rue Centrale",
zipCode: "69007",
city: "Lyon",
deliveryDelay: 5,
products: []
},
{
name: "StageLight FX",
email: "support@stagelightfx.com",
phone: "+33 5 55 74 99 31",
address: "99 Boulevard du Progrès",
zipCode: "31000",
city: "Toulouse",
deliveryDelay: 7,
products: []
},
{
name: "NovaSpark",
email: "hello@novaspark.fr",
phone: "+33 3 29 55 11 88",
address: "7 Rue de la Source",
zipCode: "54000",
city: "Nancy",
deliveryDelay: 4,
products: []
},
{
name: "FXWare",
email: "contact@fxware.eu",
phone: "+33 4 75 55 66 44",
address: "123 Route du Nord",
zipCode: "38000",
city: "Grenoble",
deliveryDelay: 6,
products: []
},
{
name: "PyroSet",
email: "info@pyroset.com",
phone: "+33 1 61 73 55 00",
address: "5 Chemin des Prés",
zipCode: "95000",
city: "Cergy",
deliveryDelay: 2,
products: []
},
{
name: "SkyFX",
email: "support@skyfx.fr",
phone: "+33 6 55 88 22 11",
address: "1 Rue du Ciel",
zipCode: "33000",
city: "Bordeaux",
deliveryDelay: 5,
products: []
},
{
name: "SparkLab",
email: "sales@sparklab.eu",
phone: "+33 2 33 55 77 12",
address: "33 Rue du Port",
zipCode: "14000",
city: "Caen",
deliveryDelay: 4,
products: []
}
];
delete() { async ngOnInit() {
return await this.fetchSuppliers();
}
async fetchSuppliers() {
this.suppliersLoading.set(true)
try {
const suppliers = await firstValueFrom(this.suppliersService.getAllSuppliersEndpoint())
this.suppliers.set(suppliers);
} catch (e) {
this.notificationService.error(
'Erreur',
'Erreur de communication avec l\'API'
)
}
this.suppliersLoading.set(false)
}
async delete(supplier:number) {
try {
await firstValueFrom(this.suppliersService.deleteSupplierEndpoint(supplier))
this.notificationService.success(
'Success',
'Suppression effectuée'
)
} catch (e) {
this.notificationService.error(
'Erreur',
'Impossible de supprimer la ligne'
)
}
await this.fetchSuppliers();
}
async edit(id: number, updateSupplierComponent: SupplierForm) {
if (updateSupplierComponent.supplierForm.invalid) {
this.notificationService.error(
'Erreur',
'Erreur d\'écriture dans le formulaire'
)
return;
}
try {
const suppliers = updateSupplierComponent.supplierForm.getRawValue();
await firstValueFrom(this.suppliersService.updateSupplierEndpoint(id, suppliers))
this.notificationService.success(
'Success',
'Fournisseur modifié'
)
} catch (e) {
console.error(e);
this.notificationService.error(
'Erreur',
'Erreur lors de la modification'
)
} }
} }
selectedSupplier: GetSupplierDto | null = null;
openEditModal(supplier: GetSupplierDto) {
this.selectedSupplier = { ...supplier };
this.modal().showModal();
}
async onModalOk(supplierId: number, updateSupplierComponent: SupplierForm, modal: ModalNav) {
if (!this.selectedSupplier) return;
await this.edit(supplierId, updateSupplierComponent);
updateSupplierComponent.supplierForm.reset();
modal.isVisible = false;
await this.fetchSuppliers();
}
onModalCancel(modal: ModalNav) {
modal.isVisible = false;
}
}

View File

@@ -1,13 +1,18 @@
<div class="flex mt-2"> <div class="flex mt-2">
<app-modal-button type="primary" name="Ajouter un fournisseur"> <app-modal-button #modalButton
<app-supplier-form></app-supplier-form> type="primary"
name="Ajouter un fournisseur"
(ok)="onModalOk()"
(cancel)="onModalCancel()">
<app-supplier-form #supplierForm></app-supplier-form>
</app-modal-button> </app-modal-button>
<div class="ml-95 w-150"> <div class="ml-95 w-150">
<app-search class="w-full"></app-search> <app-search></app-search>
</div> </div>
</div> </div>
<div class="mt-1"> <div class="mt-1">
<app-supplier-table></app-supplier-table> <app-supplier-table #supplierTable></app-supplier-table>
</div> </div>

View File

@@ -1,8 +1,11 @@
import { Component } from '@angular/core'; import {Component, inject, viewChild} from '@angular/core';
import {Search} from "../../components/search/search"; import {Search} from "../../components/search/search";
import {ModalButton} from "../../components/modal-button/modal-button"; import {ModalButton} from "../../components/modal-button/modal-button";
import {SupplierTable} from "../../components/supplier-table/supplier-table"; import {SupplierTable} from "../../components/supplier-table/supplier-table";
import {SupplierForm} from "../../components/supplier-form/supplier-form"; import {SupplierForm} from "../../components/supplier-form/supplier-form";
import {SuppliersService} from "../../services/api";
import {NzNotificationService} from "ng-zorro-antd/notification";
import {firstValueFrom} from "rxjs";
@Component({ @Component({
selector: 'app-supplier', selector: 'app-supplier',
@@ -16,5 +19,44 @@ import {SupplierForm} from "../../components/supplier-form/supplier-form";
styleUrl: './supplier.css', styleUrl: './supplier.css',
}) })
export class Supplier { export class Supplier {
modal = viewChild.required<ModalButton>('modalButton');
createSupplier = viewChild.required<SupplierForm>('supplierForm');
supplierTable = viewChild.required<SupplierTable>('supplierTable');
private usersService = inject(SuppliersService);
private notificationService = inject(NzNotificationService)
async onModalOk() {
await this.addSupplier()
this.createSupplier().supplierForm.reset();
this.modal().isVisible = false;
await this.supplierTable().fetchSuppliers()
}
onModalCancel() {
this.modal().isVisible = false;
}
async addSupplier() {
if (this.createSupplier().supplierForm.invalid)
{
this.notificationService.error(
'Erreur',
'Erreur d\'écriture dans le formulaire'
)
}
try {
const suppliers = this.createSupplier().supplierForm.getRawValue();
await firstValueFrom(this.usersService.createSupplierEndpoint(suppliers))
this.notificationService.success(
'Success',
'Fournisseur enregistré'
)
} catch (e) {
this.notificationService.error(
'Erreur',
'Erreur d\'enregistrement'
)
}
}
} }

View File

@@ -7,6 +7,7 @@
* https://openapi-generator.tech * https://openapi-generator.tech
* Do not edit the class manually. * Do not edit the class manually.
*/ */
import { GetProductDto } from './get-product-dto';
export interface GetSupplierDto { export interface GetSupplierDto {
@@ -18,5 +19,6 @@ export interface GetSupplierDto {
zipCode?: string | null; zipCode?: string | null;
city?: string | null; city?: string | null;
deliveryDelay?: number; deliveryDelay?: number;
products?: Array<GetProductDto> | null;
} }