fix: Replace broken media thumbnails with MediaThumbnail component

Old Cloudinary URLs no longer load (account full). The new MediaThumbnail
component handles broken URLs gracefully with a fallback icon, and uses
<video preload="metadata"> for local video files to show the first frame.

- New component: client/src/components/media-thumbnail.tsx
- Updated: new-reel.tsx, new-post.tsx, media-upload.tsx,
           edit-scheduled-post-dialog.tsx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Sonnet 4.6 committed 2026-03-25 08:05:04 +01:00
1 parent 7733acbc22
commit 2744b538e3
5 files changed
+83 -66

No files matched your search

+11 -31
View File
@@ -32,7 +32,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
import { Dialog, DialogContent } from "@/components/ui/dialog";
import { useToast } from "@/hooks/use-toast";
import { apiRequest, queryClient } from "@/lib/queryClient";
import { getVideoThumbnailUrl } from "@/lib/media-utils";
import { MediaThumbnail } from "@/components/media-thumbnail";
import type { SocialPage, Media, ScheduledPost } from "@shared/schema";
import { PreviewModal } from "@/components/preview-modal";
import { DateTimePicker } from "@/components/datetime-picker";
@@ -77,21 +77,11 @@ function SortableMediaItem({
className="w-full h-full"
data-testid={`button-select-media-${media.id}`}
>
{isVideo ? (
<img
src={getVideoThumbnailUrl(media.originalUrl)}
alt={media.fileName}
className="w-full h-full object-cover"
loading="lazy"
/>
) : (
<img
src={media.facebookFeedUrl || media.originalUrl}
alt={media.fileName}
className="w-full h-full object-cover"
loading="lazy"
/>
)}
<MediaThumbnail
src={media.facebookFeedUrl || media.originalUrl}
alt={media.fileName}
type={isVideo ? 'video' : 'image'}
/>
</button>
{isSelected && (
<>
@@ -543,21 +533,11 @@ export default function NewPost() {
}`}
data-testid={`button-select-media-${media.id}`}
>
{isVideo ? (
<img
src={getVideoThumbnailUrl(media.originalUrl)}
alt={media.fileName}
className="w-full h-full object-cover"
loading="lazy"
/>
) : (
<img
src={media.facebookFeedUrl || media.originalUrl}
alt={media.fileName}
className="w-full h-full object-cover"
loading="lazy"
/>
)}
<MediaThumbnail
src={media.facebookFeedUrl || media.originalUrl}
alt={media.fileName}
type={isVideo ? 'video' : 'image'}
/>
{isSelected && (
<div className="absolute inset-0 bg-primary/10 flex items-center justify-center">
<div className="text-xs font-semibold text-primary">Sélectionnée</div>
+4 -5
View File
@@ -27,7 +27,7 @@ import {
import { useToast } from "@/hooks/use-toast";
import { apiRequest, queryClient } from "@/lib/queryClient";
import type { SocialPage, Media } from "@shared/schema";
import { getVideoThumbnailUrl } from "@/lib/media-utils";
import { MediaThumbnail } from "@/components/media-thumbnail";
import { DateTimePicker } from "@/components/datetime-picker";
interface MusicTrack {
@@ -487,11 +487,10 @@ export default function NewReel() {
: 'border-transparent hover:border-muted-foreground'
}`}
>
<img
src={getVideoThumbnailUrl(media.originalUrl)}
<MediaThumbnail
src={media.originalUrl}
alt={media.fileName}
className="w-full h-full object-cover"
loading="lazy"
type="video"
/>
{selectedVideoId === media.id && (
<div className="absolute inset-0 bg-primary/20 flex items-center justify-center">