Add loading indicators to product CRUD and dialog components

This commit is contained in:
Vincent Guillet
2025-12-03 21:46:18 +01:00
parent 1a5d3a570a
commit 00f45ae6c7
10 changed files with 323 additions and 179 deletions

View File

@@ -15,11 +15,12 @@ import {
} from '@angular/material/dialog';
import {MatIcon} from '@angular/material/icon';
import {catchError, forkJoin, of, Observable} from 'rxjs';
import {catchError, forkJoin, of, Observable, finalize} from 'rxjs';
import {PsItem} from '../../interfaces/ps-item';
import {ProductListItem} from '../../interfaces/product-list-item';
import {PrestashopService} from '../../services/prestashop.serivce';
import {MatProgressSpinner} from '@angular/material/progress-spinner';
export type ProductDialogData = {
mode: 'create' | 'edit';
@@ -38,7 +39,7 @@ type CarouselItem = { src: string; isPlaceholder: boolean };
CommonModule, ReactiveFormsModule,
MatFormField, MatLabel, MatInput, MatSelectModule, MatCheckbox,
MatButton, MatDialogActions, MatDialogContent, MatDialogTitle,
MatIcon, MatIconButton
MatIcon, MatIconButton, MatProgressSpinner
]
})
export class PsProductDialogComponent implements OnInit, OnDestroy {
@@ -51,6 +52,8 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
) {
}
isSaving = false;
mode!: 'create' | 'edit';
categories: PsItem[] = [];
manufacturers: PsItem[] = [];
@@ -265,7 +268,10 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
// -------- Save / close --------
save() {
if (this.form.invalid) return;
if (this.form.invalid || this.isSaving) return;
this.isSaving = true;
this.dialogRef.disableClose = true;
const v = this.form.getRawValue();
const effectiveDescription = (v.description ?? '').trim() || this.lastLoadedDescription;
@@ -276,7 +282,7 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
categoryId: +v.categoryId!,
manufacturerId: +v.manufacturerId!,
supplierId: +v.supplierId!,
images: this.images, // toujours les fichiers sélectionnés
images: this.images,
complete: !!v.complete,
hasManual: !!v.hasManual,
conditionLabel: v.conditionLabel || undefined,
@@ -292,10 +298,19 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
op$ = this.ps.updateProduct(this.productRow.id, dto) as Observable<unknown>;
}
op$.subscribe({
next: () => this.dialogRef.close(true),
error: (e: unknown) => alert('Erreur: ' + (e instanceof Error ? e.message : String(e)))
});
op$
.pipe(
finalize(() => {
// si la boîte de dialogue est encore ouverte, on réactive tout
this.isSaving = false;
this.dialogRef.disableClose = false;
})
)
.subscribe({
next: () => this.dialogRef.close(true),
error: (e: unknown) =>
alert('Erreur: ' + (e instanceof Error ? e.message : String(e)))
});
}
/** Extrait l'id_image depuis une URL FO Presta (.../img/p/.../<id>.jpg) */
@@ -375,6 +390,7 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
}
close() {
if (this.isSaving) return;
this.dialogRef.close(false);
}
}