d8a3f26d0b
- Chargement du catalogue Shopify au début de l'exécution (fetchAllShopifyProducts) - Vérification par SKU (ref) : si déjà présent dans Shopify → skipped, pas de création - Nouveau type d'événement 'skipped' dans CreationStreamEvent - CreationProgress affiche les produits ignorés en amber avec le SKU concerné - Résumé final inclut le compte de produits ignorés Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
67 lines
3.4 KiB
TypeScript
67 lines
3.4 KiB
TypeScript
'use client'
|
||
import type { CreationStreamEvent } from '@/types/creation'
|
||
|
||
interface Props {
|
||
events: CreationStreamEvent[]
|
||
done: boolean
|
||
}
|
||
|
||
export function CreationProgress({ events, done }: Props) {
|
||
const lastProgress = [...events].reverse().find(e => e.type === 'progress') as Extract<CreationStreamEvent, { type: 'progress' }> | undefined
|
||
const doneEvent = events.find(e => e.type === 'done') as Extract<CreationStreamEvent, { type: 'done' }> | undefined
|
||
const errors = events.filter(e => e.type === 'error') as Array<Extract<CreationStreamEvent, { type: 'error' }>>
|
||
const skipped = events.filter(e => e.type === 'skipped') as Array<Extract<CreationStreamEvent, { type: 'skipped' }>>
|
||
|
||
return (
|
||
<div className="space-y-4">
|
||
{lastProgress && !done && (
|
||
<div>
|
||
<div className="flex justify-between text-sm text-gray-300 mb-1">
|
||
<span>{lastProgress.step}</span>
|
||
<span>{lastProgress.current}/{lastProgress.total}</span>
|
||
</div>
|
||
<div className="w-full bg-slate-700 rounded-full h-2">
|
||
<div className="bg-indigo-600 h-2 rounded-full transition-all"
|
||
style={{ width: `${(lastProgress.current / lastProgress.total) * 100}%` }} />
|
||
</div>
|
||
<p className="text-xs text-gray-400 mt-1 truncate">{lastProgress.tab} — {lastProgress.title}</p>
|
||
</div>
|
||
)}
|
||
{skipped.length > 0 && (
|
||
<div className="space-y-1">
|
||
{skipped.map((e, i) => (
|
||
<div key={i} className="flex gap-2 p-2 bg-amber-900/20 border border-amber-800/40 rounded text-xs text-amber-300">
|
||
<span>⚠️</span>
|
||
<span className="font-medium">{e.title}</span>
|
||
<span className="text-amber-500">— SKU {e.sku} déjà présent dans Shopify, ignoré</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
{errors.length > 0 && (
|
||
<div className="space-y-1">
|
||
{errors.map((e, i) => (
|
||
<div key={i} className="flex gap-2 p-2 bg-red-900/30 rounded text-xs text-red-300">
|
||
<span className="font-medium">{e.title}</span>
|
||
<span className="text-red-400">— {e.message}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
{doneEvent && (
|
||
<div className={`p-4 rounded-lg ${doneEvent.summary.status === 'success' ? 'bg-green-900/30 border border-green-700' : doneEvent.summary.status === 'partial' ? 'bg-yellow-900/30 border border-yellow-700' : 'bg-red-900/30 border border-red-700'}`}>
|
||
<p className={`font-semibold ${doneEvent.summary.status === 'success' ? 'text-green-300' : doneEvent.summary.status === 'partial' ? 'text-yellow-300' : 'text-red-300'}`}>
|
||
{doneEvent.summary.status === 'success' ? '✓ Terminé' : doneEvent.summary.status === 'partial' ? '⚠ Partiel' : '✗ Erreur'}
|
||
</p>
|
||
<p className="text-sm text-gray-300 mt-1">
|
||
{doneEvent.summary.created} créé{doneEvent.summary.created > 1 ? 's' : ''}
|
||
{doneEvent.summary.skipped > 0 && ` — ${doneEvent.summary.skipped} déjà existant${doneEvent.summary.skipped > 1 ? 's' : ''} (ignorés)`}
|
||
{doneEvent.summary.errors > 0 && ` — ${doneEvent.summary.errors} erreur${doneEvent.summary.errors > 1 ? 's' : ''}`}
|
||
</p>
|
||
</div>
|
||
)}
|
||
{!done && !lastProgress && <p className="text-gray-400 text-sm">Démarrage…</p>}
|
||
</div>
|
||
)
|
||
}
|