From b756c9fa2d18da3c6cb9d6321cf85d8351ba6c95 Mon Sep 17 00:00:00 2001 From: Vincent Guillet Date: Tue, 18 Nov 2025 16:32:29 +0100 Subject: [PATCH] feat: implement image carousel in product dialog; enhance image upload handling and preview functionality --- .../ps-product-crud.component.css | 14 +++ .../ps-product-crud.component.ts | 37 ++++---- .../ps-product-dialog.component.css | 94 ++++++++++++++++++- .../ps-product-dialog.component.html | 64 ++++++++++--- .../ps-product-dialog.component.ts | 88 +++++++++++++++-- client/src/app/interfaces/ps-product.ts | 1 + client/src/app/services/prestashop.serivce.ts | 62 ++++++++---- 7 files changed, 302 insertions(+), 58 deletions(-) diff --git a/client/src/app/components/ps-product-crud/ps-product-crud.component.css b/client/src/app/components/ps-product-crud/ps-product-crud.component.css index c87c629..65d931e 100644 --- a/client/src/app/components/ps-product-crud/ps-product-crud.component.css +++ b/client/src/app/components/ps-product-crud/ps-product-crud.component.css @@ -17,3 +17,17 @@ table { width: 100%; } + +.prod-cell { + display: flex; + align-items: center; + gap: 8px; +} + +.prod-thumb { + width: 32px; + height: 32px; + object-fit: cover; + border-radius: 4px; + flex-shrink: 0; +} diff --git a/client/src/app/components/ps-product-crud/ps-product-crud.component.ts b/client/src/app/components/ps-product-crud/ps-product-crud.component.ts index 3a7d5fc..56450b4 100644 --- a/client/src/app/components/ps-product-crud/ps-product-crud.component.ts +++ b/client/src/app/components/ps-product-crud/ps-product-crud.component.ts @@ -2,8 +2,8 @@ import {Component, inject, OnInit, ViewChild} from '@angular/core'; import {CommonModule} from '@angular/common'; import { MatCell, MatCellDef, MatColumnDef, MatHeaderCell, MatHeaderCellDef, - MatHeaderRow, MatHeaderRowDef, MatNoDataRow, MatRow, MatRowDef, - MatTable, MatTableDataSource + MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef, + MatNoDataRow, MatTable, MatTableDataSource } from '@angular/material/table'; import {MatPaginator, MatPaginatorModule} from '@angular/material/paginator'; import {MatSort, MatSortModule} from '@angular/material/sort'; @@ -13,6 +13,7 @@ import {MatButton, MatIconButton} from '@angular/material/button'; import {MatIcon} from '@angular/material/icon'; import {FormBuilder, ReactiveFormsModule} from '@angular/forms'; import {MatDialog, MatDialogModule} from '@angular/material/dialog'; +import {forkJoin} from 'rxjs'; import {PsItem} from '../../interfaces/ps-item'; import {ProductListItem} from '../../interfaces/product-list-item'; @@ -60,19 +61,23 @@ export class PsProductCrudComponent implements OnInit { filterCtrl = this.fb.control(''); ngOnInit(): void { - // charger référentiels en parallèle - Promise.all([ - this.ps.list('categories').toPromise(), - this.ps.list('manufacturers').toPromise(), - this.ps.list('suppliers').toPromise() - ]).then(([cats, mans, sups]) => { - this.categories = cats ?? []; - this.catMap = new Map(this.categories.map(x => [x.id, x.name])); - this.manufacturers = mans ?? []; - this.manMap = new Map(this.manufacturers.map(x => [x.id, x.name])); - this.suppliers = sups ?? []; - this.supMap = new Map(this.suppliers.map(x => [x.id, x.name])); - this.reload(); + forkJoin({ + cats: this.ps.list('categories'), + mans: this.ps.list('manufacturers'), + sups: this.ps.list('suppliers') + }).subscribe({ + next: ({cats, mans, sups}) => { + this.categories = cats ?? []; + this.catMap = new Map(this.categories.map(x => [x.id, x.name])); + this.manufacturers = mans ?? []; + this.manMap = new Map(this.manufacturers.map(x => [x.id, x.name])); + this.suppliers = sups ?? []; + this.supMap = new Map(this.suppliers.map(x => [x.id, x.name])); + this.reload(); + }, + error: err => { + console.error('Erreur lors du chargement des référentiels', err); + } }); // filtre client @@ -115,7 +120,7 @@ export class PsProductCrudComponent implements OnInit { } private bindProducts(p: (ProductListItem & { priceHt?: number })[]) { - const vat = 0.20; // valeur fixe utilisée pour calcul TTC en liste + const vat = 0.2; this.dataSource.data = p.map(x => ({ ...x, categoryName: x.id_category_default ? (this.catMap.get(x.id_category_default) ?? '') : '', diff --git a/client/src/app/components/ps-product-dialog/ps-product-dialog.component.css b/client/src/app/components/ps-product-dialog/ps-product-dialog.component.css index eaf109d..2532832 100644 --- a/client/src/app/components/ps-product-dialog/ps-product-dialog.component.css +++ b/client/src/app/components/ps-product-dialog/ps-product-dialog.component.css @@ -23,14 +23,98 @@ align-items: center; } -.thumbs { - display: flex; +/* ===== Nouveau : carrousel ===== */ + +.carousel { + grid-column: span 12; + display: grid; gap: 8px; - flex-wrap: wrap; } -.thumbs img { +.carousel-main { + position: relative; + min-height: 220px; + display: flex; + align-items: center; + justify-content: center; + background: #f5f5f5; + border-radius: 8px; + overflow: hidden; +} + +.carousel-main img { + max-width: 100%; + max-height: 280px; + object-fit: contain; +} + +.carousel-nav-btn { + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.carousel-nav-btn.left { + left: 4px; +} + +.carousel-nav-btn.right { + right: 4px; +} + +.carousel-placeholder { + text-align: center; + color: #757575; + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + cursor: pointer; +} + +.carousel-placeholder mat-icon { + font-size: 40px; +} + +/* Bandeau de vignettes */ + +.carousel-thumbs { + display: flex; + gap: 8px; + overflow-x: auto; +} + +.thumb-item { + width: 64px; height: 64px; border-radius: 4px; - box-shadow: 0 1px 4px rgba(0, 0, 0, .2); + overflow: hidden; + border: 2px solid transparent; + flex: 0 0 auto; + cursor: pointer; +} + +.thumb-item.active { + border-color: #1976d2; +} + +.thumb-img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.thumb-placeholder { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background: #eeeeee; + color: #575656; + border: 1px dashed #bdbdbd; +} + +.thumb-placeholder mat-icon { + font-size: 28px; } diff --git a/client/src/app/components/ps-product-dialog/ps-product-dialog.component.html b/client/src/app/components/ps-product-dialog/ps-product-dialog.component.html index 574bafe..a71ddb5 100644 --- a/client/src/app/components/ps-product-dialog/ps-product-dialog.component.html +++ b/client/src/app/components/ps-product-dialog/ps-product-dialog.component.html @@ -2,22 +2,57 @@
- -
- - -
+ + +