fix: fall back to Bunny Storage for cover images
This commit is contained in:
39
components/CourseCoverImage.tsx
Normal file
39
components/CourseCoverImage.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
type CourseCoverImageProps = Omit<React.ImgHTMLAttributes<HTMLImageElement>, 'src' | 'onError'> & {
|
||||
source: string;
|
||||
onFinalError?: () => void;
|
||||
};
|
||||
|
||||
const fallbackCoverUrl = (source: string) => {
|
||||
try {
|
||||
const parsed = new URL(source, window.location.origin);
|
||||
const filename = parsed.pathname.split('/').pop() || '';
|
||||
if (!/^[0-9a-f]{8}-[0-9a-f-]{27}\.(?:jpg|png|webp)$/i.test(filename)) return null;
|
||||
const apiBase = import.meta.env.VITE_API_URL || '/api/v1';
|
||||
return `${apiBase}/courses/covers/${filename}`;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const CourseCoverImage: React.FC<CourseCoverImageProps> = ({ source, onFinalError, ...props }) => {
|
||||
const fallbackUrl = useMemo(() => fallbackCoverUrl(source), [source]);
|
||||
const [usingFallback, setUsingFallback] = useState(false);
|
||||
|
||||
useEffect(() => setUsingFallback(false), [source]);
|
||||
|
||||
return (
|
||||
<img
|
||||
{...props}
|
||||
src={usingFallback && fallbackUrl ? fallbackUrl : source}
|
||||
onError={() => {
|
||||
if (!usingFallback && fallbackUrl) {
|
||||
setUsingFallback(true);
|
||||
return;
|
||||
}
|
||||
onFinalError?.();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user