Skip to content

Commit 35ebc8d

Browse files
make CapCard more conservative with upload status
1 parent d4b9b0c commit 35ebc8d

File tree

3 files changed

+72
-73
lines changed

3 files changed

+72
-73
lines changed

apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx

Lines changed: 56 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ import { useDashboardContext } from "@/app/(org)/dashboard/Contexts";
3232
import ProgressCircle, {
3333
useUploadProgress,
3434
} from "@/app/s/[videoId]/_components/ProgressCircle";
35-
import { VideoThumbnail } from "@/components/VideoThumbnail";
35+
import {
36+
ImageLoadingStatus,
37+
VideoThumbnail,
38+
} from "@/components/VideoThumbnail";
3639
import { useEffectMutation } from "@/lib/EffectRuntime";
3740
import { withRpc } from "@/lib/Rpcs";
3841
import { PasswordDialog } from "../PasswordDialog";
@@ -172,6 +175,7 @@ export const CapCard = ({
172175
cap.id,
173176
cap.hasActiveUpload || false,
174177
);
178+
const [imageStatus, setImageStatus] = useState<ImageLoadingStatus>("loading");
175179

176180
// Helper function to create a drag preview element
177181
const createDragPreview = (text: string): HTMLElement => {
@@ -496,87 +500,72 @@ export const CapCard = ({
496500
</div>
497501
</div>
498502
)}
503+
499504
<div className="relative">
500505
<Link
501506
className={clsx(
502-
"block group",
507+
"relative",
508+
// "block group",
503509
anyCapSelected && "cursor-pointer pointer-events-none",
504510
)}
505511
onClick={(e) => {
506512
if (isDeleting) e.preventDefault();
507513
}}
508514
href={`/s/${cap.id}`}
509515
>
510-
{uploadProgress ? (
511-
<div className="overflow-hidden relative mx-auto w-full h-full rounded-t-xl border-b border-gray-3 aspect-video bg-black z-5">
512-
<div className="flex absolute inset-0 justify-center items-center rounded-t-xl">
513-
{uploadProgress.status === "failed" ? (
514-
<div className="flex flex-col items-center">
515-
<div className="flex justify-center items-center mb-2 w-8 h-8 bg-red-500 rounded-full">
516-
<FontAwesomeIcon
517-
icon={faVideo}
518-
className="text-white size-3"
516+
{imageStatus !== "success" && uploadProgress ? (
517+
<div className="absolute inset-0 w-full h-full z-20">
518+
<div className="overflow-hidden relative mx-auto w-full h-full rounded-t-xl border-b border-gray-3 aspect-video bg-black z-5">
519+
<div className="flex absolute inset-0 justify-center items-center rounded-t-xl">
520+
{uploadProgress.status === "failed" ? (
521+
<div className="flex flex-col items-center">
522+
<div className="flex justify-center items-center mb-2 w-8 h-8 bg-red-500 rounded-full">
523+
<FontAwesomeIcon
524+
icon={faVideo}
525+
className="text-white size-3"
526+
/>
527+
</div>
528+
<p className="text-[13px] text-center text-white">
529+
Upload failed
530+
</p>
531+
</div>
532+
) : (
533+
<div className="relative size-20 md:size-16">
534+
<ProgressCircle
535+
progressTextClassName="md:!text-[11px]"
536+
subTextClassName="!mt-0 md:!text-[7px] !text-[10px] mb-1"
537+
className="md:scale-[1.5] scale-[1.2]"
538+
progress={uploadProgress.progress}
519539
/>
520540
</div>
521-
<p className="text-[13px] text-center text-white">
522-
Upload failed
523-
</p>
524-
</div>
525-
) : (
526-
<div className="relative size-20 md:size-16">
527-
<ProgressCircle
528-
progressTextClassName="md:!text-[11px]"
529-
subTextClassName="!mt-0 md:!text-[7px] !text-[10px] mb-1"
530-
className="md:scale-[1.5] scale-[1.2]"
531-
progress={uploadProgress.progress}
532-
/>
533-
</div>
534-
)}
535-
</div>
536-
</div>
537-
) : (
538-
<VideoThumbnail
539-
videoDuration={cap.duration}
540-
imageClass={clsx(
541-
anyCapSelected
542-
? "opacity-50"
543-
: isDropdownOpen
544-
? "opacity-30"
545-
: "group-hover:opacity-30",
546-
"transition-opacity duration-200",
547-
// uploadProgress && "opacity-30",
548-
)}
549-
videoId={cap.id}
550-
alt={`${cap.name} Thumbnail`}
551-
/>
552-
)}
553-
</Link>
554-
{uploadProgress && (
555-
<div className="flex absolute inset-0 z-50 justify-center items-center bg-black rounded-t-xl">
556-
{uploadProgress.status === "failed" ? (
557-
<div className="flex flex-col items-center">
558-
<div className="flex justify-center items-center mb-2 w-8 h-8 bg-red-500 rounded-full">
559-
<FontAwesomeIcon
560-
icon={faVideo}
561-
className="text-white size-3"
562-
/>
541+
)}
563542
</div>
564-
<p className="text-[13px] text-center text-white">
565-
Upload failed
566-
</p>
567-
</div>
568-
) : (
569-
<div className="relative size-20 md:size-16">
570-
<ProgressCircle
571-
progressTextClassName="md:!text-[11px]"
572-
subTextClassName="!mt-0 md:!text-[7px] !text-[10px] mb-1"
573-
className="md:scale-[1.5] scale-[1.2]"
574-
progress={uploadProgress.progress}
575-
/>
576543
</div>
544+
</div>
545+
) : null}
546+
547+
<VideoThumbnail
548+
videoDuration={cap.duration}
549+
imageClass={clsx(
550+
anyCapSelected
551+
? "opacity-50"
552+
: isDropdownOpen
553+
? "opacity-30"
554+
: "group-hover:opacity-30",
555+
"transition-opacity duration-200",
577556
)}
578-
</div>
579-
)}
557+
containerClass={clsx(
558+
imageStatus !== "success" && uploadProgress
559+
? "display-none"
560+
: "",
561+
"absolute inset-0",
562+
)}
563+
videoId={cap.id}
564+
alt={`${cap.name} Thumbnail`}
565+
imageStatus={imageStatus}
566+
setImageStatus={setImageStatus}
567+
/>
568+
</Link>
580569
</div>
581570
<div
582571
className={clsx(

apps/web/app/(org)/dashboard/spaces/[spaceId]/components/VideoCard.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ import { AnimatePresence, motion } from "framer-motion";
33
import { Check, Minus, Plus } from "lucide-react";
44
import moment from "moment";
55
import type React from "react";
6-
import { memo } from "react";
6+
import { memo, useState } from "react";
77
import { Tooltip } from "@/components/Tooltip";
8-
import { VideoThumbnail } from "@/components/VideoThumbnail";
8+
import {
9+
ImageLoadingStatus,
10+
VideoThumbnail,
11+
} from "@/components/VideoThumbnail";
912
import type { VideoData } from "./AddVideosDialogBase";
1013

1114
interface VideoCardProps {
@@ -22,6 +25,9 @@ const VideoCard: React.FC<VideoCardProps> = memo(
2225
? new Date(video.metadata.customCreatedAt)
2326
: video.createdAt;
2427

28+
const [imageStatus, setImageStatus] =
29+
useState<ImageLoadingStatus>("loading");
30+
2531
return (
2632
<div
2733
onClick={onToggle}
@@ -104,6 +110,8 @@ const VideoCard: React.FC<VideoCardProps> = memo(
104110
alt={`${video.name} Thumbnail`}
105111
objectFit="cover"
106112
containerClass="!h-full !rounded-lg !border-b-0"
113+
imageStatus={imageStatus}
114+
setImageStatus={setImageStatus}
107115
/>
108116
</div>
109117

apps/web/components/VideoThumbnail.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ import moment from "moment";
55
import Image from "next/image";
66
import { memo, useEffect, useRef, useState } from "react";
77

8+
export type ImageLoadingStatus = "loading" | "success" | "error";
9+
810
interface VideoThumbnailProps {
911
videoId: string;
1012
alt: string;
1113
imageClass?: string;
1214
objectFit?: string;
1315
containerClass?: string;
1416
videoDuration?: number;
17+
imageStatus: ImageLoadingStatus;
18+
setImageStatus: (status: ImageLoadingStatus) => void;
1519
}
1620

1721
const formatDuration = (durationSecs: number) => {
@@ -61,16 +65,14 @@ export const VideoThumbnail: React.FC<VideoThumbnailProps> = memo(
6165
objectFit = "cover",
6266
containerClass,
6367
videoDuration,
68+
imageStatus,
69+
setImageStatus,
6470
}) => {
6571
const imageUrl = useQuery(imageUrlQuery(videoId));
6672
const imageRef = useRef<HTMLImageElement>(null);
6773

6874
const randomGradient = `linear-gradient(to right, ${generateRandomGrayScaleColor()}, ${generateRandomGrayScaleColor()})`;
6975

70-
const [imageStatus, setImageStatus] = useState<
71-
"loading" | "error" | "success"
72-
>("loading");
73-
7476
useEffect(() => {
7577
if (imageRef.current?.complete && imageRef.current.naturalWidth !== 0) {
7678
setImageStatus("success");

0 commit comments

Comments
 (0)