feat: affichage images produit dans la liste avec thumbnail et compteur
This commit is contained in:
@@ -19,6 +19,7 @@ export async function GET(req: NextRequest): Promise<NextResponse<ProductListRes
|
|||||||
stock: p.stock,
|
stock: p.stock,
|
||||||
status: p.status as CatalogProduct['status'],
|
status: p.status as CatalogProduct['status'],
|
||||||
shopifyUrl: `https://${domain}/admin/products/${p.shopifyId}`,
|
shopifyUrl: `https://${domain}/admin/products/${p.shopifyId}`,
|
||||||
|
images: p.images ?? [],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if (statusFilter !== 'all') {
|
if (statusFilter !== 'all') {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export function ProductTable({ products, loading }: Props) {
|
|||||||
<thead>
|
<thead>
|
||||||
<tr className="text-left text-gray-400 border-b border-slate-700">
|
<tr className="text-left text-gray-400 border-b border-slate-700">
|
||||||
<th className="pb-3 pr-4 font-medium">Référence</th>
|
<th className="pb-3 pr-4 font-medium">Référence</th>
|
||||||
|
<th className="pb-3 pr-4 font-medium">Images</th>
|
||||||
<th className="pb-3 pr-4 font-medium">Titre</th>
|
<th className="pb-3 pr-4 font-medium">Titre</th>
|
||||||
<th className="pb-3 pr-4 font-medium">Prix</th>
|
<th className="pb-3 pr-4 font-medium">Prix</th>
|
||||||
<th className="pb-3 pr-4 font-medium">Stock</th>
|
<th className="pb-3 pr-4 font-medium">Stock</th>
|
||||||
@@ -48,6 +49,18 @@ export function ProductTable({ products, loading }: Props) {
|
|||||||
{displayed.map((p) => (
|
{displayed.map((p) => (
|
||||||
<tr key={p.shopifyId} className="border-b border-slate-700/50 hover:bg-slate-700/30 transition-colors">
|
<tr key={p.shopifyId} className="border-b border-slate-700/50 hover:bg-slate-700/30 transition-colors">
|
||||||
<td className="py-3 pr-4 font-mono text-indigo-300">{p.ref}</td>
|
<td className="py-3 pr-4 font-mono text-indigo-300">{p.ref}</td>
|
||||||
|
<td className="py-3 pr-4">
|
||||||
|
{p.images.length > 0 ? (
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<img src={p.images[0]} alt="" className="w-8 h-8 object-cover rounded border border-slate-600" />
|
||||||
|
{p.images.length > 1 && (
|
||||||
|
<span className="text-xs text-gray-400">+{p.images.length - 1}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<span className="text-xs text-gray-600">—</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
<td className="py-3 pr-4 text-white">{p.title}</td>
|
<td className="py-3 pr-4 text-white">{p.title}</td>
|
||||||
<td className="py-3 pr-4 text-gray-300">{p.price} €</td>
|
<td className="py-3 pr-4 text-gray-300">{p.price} €</td>
|
||||||
<td className="py-3 pr-4 text-gray-300">{p.stock}</td>
|
<td className="py-3 pr-4 text-gray-300">{p.stock}</td>
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ interface ShopifyAPIProduct {
|
|||||||
body_html: string
|
body_html: string
|
||||||
status: string
|
status: string
|
||||||
variants: ShopifyVariant[]
|
variants: ShopifyVariant[]
|
||||||
|
images: Array<{ src: string }>
|
||||||
}
|
}
|
||||||
|
|
||||||
function toSyncProduct(p: ShopifyAPIProduct): ShopifyProductFull {
|
function toSyncProduct(p: ShopifyAPIProduct): ShopifyProductFull {
|
||||||
@@ -43,6 +44,7 @@ function toSyncProduct(p: ShopifyAPIProduct): ShopifyProductFull {
|
|||||||
price: p.variants[0]?.price ?? '0.00',
|
price: p.variants[0]?.price ?? '0.00',
|
||||||
stock: p.variants[0]?.inventory_quantity ?? 0,
|
stock: p.variants[0]?.inventory_quantity ?? 0,
|
||||||
status: p.status === 'active' ? 'active' : 'draft',
|
status: p.status === 'active' ? 'active' : 'draft',
|
||||||
|
images: (p.images ?? []).map(i => i.src),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +71,7 @@ async function fetchByStatus(status: 'active' | 'draft'): Promise<ShopifyProduct
|
|||||||
const all: ShopifyProductFull[] = []
|
const all: ShopifyProductFull[] = []
|
||||||
|
|
||||||
let url: string | null =
|
let url: string | null =
|
||||||
`${baseUrl}/products.json?limit=250&fields=id,title,handle,status,body_html,variants&status=${status}`
|
`${baseUrl}/products.json?limit=250&fields=id,title,handle,status,body_html,variants,images&status=${status}`
|
||||||
|
|
||||||
while (url) {
|
while (url) {
|
||||||
const res = await fetch(url, { headers })
|
const res = await fetch(url, { headers })
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ export interface CatalogProduct {
|
|||||||
price: string // "29.99"
|
price: string // "29.99"
|
||||||
stock: number // inventory_quantity variante 1
|
stock: number // inventory_quantity variante 1
|
||||||
status: 'active' | 'draft' | 'archived'
|
status: 'active' | 'draft' | 'archived'
|
||||||
shopifyUrl: string // https://materiaux-destock.myshopify.com/admin/products/<id>
|
shopifyUrl: string
|
||||||
|
images: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Filtres appliqués à la liste */
|
/** Filtres appliqués à la liste */
|
||||||
|
|||||||
+2
-1
@@ -13,7 +13,8 @@ export interface SyncProduct {
|
|||||||
|
|
||||||
/** Produit Shopify enrichi pour la comparaison */
|
/** Produit Shopify enrichi pour la comparaison */
|
||||||
export interface ShopifyProductFull extends SyncProduct {
|
export interface ShopifyProductFull extends SyncProduct {
|
||||||
shopifyId: string // ID numérique Shopify (string)
|
shopifyId: string
|
||||||
|
images?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Un changement unitaire calculé par computeDiff */
|
/** Un changement unitaire calculé par computeDiff */
|
||||||
|
|||||||
Reference in New Issue
Block a user