refactor: simplify CoverClient component

This commit is contained in:
2026-02-27 09:41:58 +01:00
parent 38c7e59366
commit bcfd602353

View File

@@ -1,7 +1,6 @@
"use client";
import { ImageOff } from "lucide-react";
import { useState, useEffect, useRef } from "react";
import { useState, useRef, useEffect } from "react";
import { cn } from "@/lib/utils";
import { ImageLoader } from "@/components/ui/image-loader";
@@ -18,96 +17,31 @@ export const CoverClient = ({
className,
isCompleted = false,
}: CoverClientProps) => {
const [imageError, setImageError] = useState(false);
const imgRef = useRef<HTMLImageElement>(null);
const [isLoading, setIsLoading] = useState(true);
const [retryCount, setRetryCount] = useState(0);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
// Reset état quand l'URL change
useEffect(() => {
setImageError(false);
setIsLoading(true);
setRetryCount(0);
}, [imageUrl]);
// Timeout de sécurité : si l'image ne se charge pas en 30 secondes, on arrête le loading
useEffect(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
const img = imgRef.current;
if (img?.complete && img.naturalWidth > 0) {
setIsLoading(false);
}
timeoutRef.current = setTimeout(() => {
if (isLoading) {
setIsLoading(false);
setImageError(true);
}
}, 30000);
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, [imageUrl, isLoading, retryCount]);
// Si en erreur, réessayer automatiquement après 2 secondes
useEffect(() => {
if (imageError) {
const timer = setTimeout(() => {
setImageError(false);
setIsLoading(true);
setRetryCount((prev) => prev + 1);
}, 2000);
return () => clearTimeout(timer);
}
}, [imageError]);
const handleLoad = () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
setIsLoading(false);
setImageError(false);
};
const handleError = () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
setImageError(true);
setIsLoading(false);
};
// Ajouter un timestamp pour forcer le rechargement en cas de retry
const imageUrlWithRetry =
retryCount > 0
? `${imageUrl}${imageUrl.includes("?") ? "&" : "?"}retry=${retryCount}`
: imageUrl;
if (imageError) {
return (
<div className="w-full h-full flex items-center justify-center bg-muted/80 backdrop-blur-md rounded-lg">
<ImageOff className="w-12 h-12 text-muted-foreground" />
</div>
);
}
}, []);
return (
<div className="relative w-full h-full">
<ImageLoader isLoading={isLoading} />
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={imageUrlWithRetry}
ref={imgRef}
src={imageUrl}
alt={alt}
loading="lazy"
className={cn(
"absolute inset-0 w-full h-full object-cover transition-opacity duration-300 rounded-lg",
"absolute inset-0 w-full h-full object-cover rounded-lg",
isCompleted && "opacity-50",
className
)}
onError={handleError}
onLoad={handleLoad}
onLoad={() => setIsLoading(false)}
onError={() => setIsLoading(false)}
/>
</div>
);