feat: enhance image loading in CoverClient component with timeout handling and error management, update PreferencesContext to initialize loading state as false, and refine type casting in PreferencesService
This commit is contained in:
@@ -1,8 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { ImageOff } from "lucide-react";
|
import { ImageOff } from "lucide-react";
|
||||||
import Image from "next/image";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { useState } 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";
|
||||||
|
|
||||||
@@ -21,6 +20,38 @@ export const CoverClient = ({
|
|||||||
}: CoverClientProps) => {
|
}: CoverClientProps) => {
|
||||||
const [imageError, setImageError] = useState(false);
|
const [imageError, setImageError] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
|
// Timeout de sécurité : si l'image ne se charge pas en 10 secondes, on arrête le loading
|
||||||
|
useEffect(() => {
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
if (isLoading) {
|
||||||
|
console.warn("Image loading timeout for:", imageUrl);
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [imageUrl, isLoading]);
|
||||||
|
|
||||||
|
const handleLoad = () => {
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
}
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleError = () => {
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
}
|
||||||
|
console.error("Image loading error for:", imageUrl);
|
||||||
|
setImageError(true);
|
||||||
|
};
|
||||||
|
|
||||||
if (imageError) {
|
if (imageError) {
|
||||||
return (
|
return (
|
||||||
@@ -33,19 +64,18 @@ export const CoverClient = ({
|
|||||||
return (
|
return (
|
||||||
<div className="relative w-full h-full">
|
<div className="relative w-full h-full">
|
||||||
<ImageLoader isLoading={isLoading} />
|
<ImageLoader isLoading={isLoading} />
|
||||||
<Image
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
src={imageUrl}
|
src={imageUrl}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
fill
|
loading="lazy"
|
||||||
className={cn(
|
className={cn(
|
||||||
"object-cover transition-opacity duration-300 rounded-lg",
|
"absolute inset-0 w-full h-full object-cover transition-opacity duration-300 rounded-lg",
|
||||||
isCompleted && "opacity-50",
|
isCompleted && "opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
onError={() => setImageError(true)}
|
onError={handleError}
|
||||||
onLoad={() => setIsLoading(false)}
|
onLoad={handleLoad}
|
||||||
loading="lazy"
|
|
||||||
unoptimized
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export function PreferencesProvider({
|
|||||||
const [preferences, setPreferences] = useState<UserPreferences>(
|
const [preferences, setPreferences] = useState<UserPreferences>(
|
||||||
initialPreferences || defaultPreferences
|
initialPreferences || defaultPreferences
|
||||||
);
|
);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const fetchPreferences = async () => {
|
const fetchPreferences = async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export class PreferencesService {
|
|||||||
showOnlyUnread: preferences.showOnlyUnread,
|
showOnlyUnread: preferences.showOnlyUnread,
|
||||||
debug: preferences.debug,
|
debug: preferences.debug,
|
||||||
displayMode: preferences.displayMode as UserPreferences["displayMode"],
|
displayMode: preferences.displayMode as UserPreferences["displayMode"],
|
||||||
background: (preferences.background as Prisma.JsonValue) as BackgroundPreferences,
|
background: preferences.background as unknown as BackgroundPreferences,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof AppError) {
|
if (error instanceof AppError) {
|
||||||
@@ -65,7 +65,7 @@ export class PreferencesService {
|
|||||||
showOnlyUnread: preferences.showOnlyUnread ?? defaultPreferences.showOnlyUnread,
|
showOnlyUnread: preferences.showOnlyUnread ?? defaultPreferences.showOnlyUnread,
|
||||||
debug: preferences.debug ?? defaultPreferences.debug,
|
debug: preferences.debug ?? defaultPreferences.debug,
|
||||||
displayMode: preferences.displayMode ?? defaultPreferences.displayMode,
|
displayMode: preferences.displayMode ?? defaultPreferences.displayMode,
|
||||||
background: (preferences.background ?? defaultPreferences.background) as Prisma.InputJsonValue,
|
background: (preferences.background ?? defaultPreferences.background) as unknown as Prisma.InputJsonValue,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ export class PreferencesService {
|
|||||||
showOnlyUnread: updatedPreferences.showOnlyUnread,
|
showOnlyUnread: updatedPreferences.showOnlyUnread,
|
||||||
debug: updatedPreferences.debug,
|
debug: updatedPreferences.debug,
|
||||||
displayMode: updatedPreferences.displayMode as UserPreferences["displayMode"],
|
displayMode: updatedPreferences.displayMode as UserPreferences["displayMode"],
|
||||||
background: (updatedPreferences.background as Prisma.JsonValue) as BackgroundPreferences,
|
background: updatedPreferences.background as unknown as BackgroundPreferences,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof AppError) {
|
if (error instanceof AppError) {
|
||||||
|
|||||||
Reference in New Issue
Block a user