refactor: simplify CoverClient component
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { ImageOff } from "lucide-react";
|
import { useState, useRef, useEffect } from "react";
|
||||||
import { useState, useEffect, useRef } from "react";
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { ImageLoader } from "@/components/ui/image-loader";
|
import { ImageLoader } from "@/components/ui/image-loader";
|
||||||
|
|
||||||
@@ -18,96 +17,31 @@ export const CoverClient = ({
|
|||||||
className,
|
className,
|
||||||
isCompleted = false,
|
isCompleted = false,
|
||||||
}: CoverClientProps) => {
|
}: CoverClientProps) => {
|
||||||
const [imageError, setImageError] = useState(false);
|
const imgRef = useRef<HTMLImageElement>(null);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [retryCount, setRetryCount] = useState(0);
|
|
||||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
|
|
||||||
// Reset état quand l'URL change
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setImageError(false);
|
const img = imgRef.current;
|
||||||
setIsLoading(true);
|
if (img?.complete && img.naturalWidth > 0) {
|
||||||
setRetryCount(0);
|
setIsLoading(false);
|
||||||
}, [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);
|
|
||||||
}
|
}
|
||||||
|
}, []);
|
||||||
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 (
|
return (
|
||||||
<div className="relative w-full h-full">
|
<div className="relative w-full h-full">
|
||||||
<ImageLoader isLoading={isLoading} />
|
<ImageLoader isLoading={isLoading} />
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
||||||
<img
|
<img
|
||||||
src={imageUrlWithRetry}
|
ref={imgRef}
|
||||||
|
src={imageUrl}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
className={cn(
|
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",
|
isCompleted && "opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
onError={handleError}
|
onLoad={() => setIsLoading(false)}
|
||||||
onLoad={handleLoad}
|
onError={() => setIsLoading(false)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user