import { CheckCircleIcon, PhotoIcon } from "@heroicons/react/24/outline"; import type { ChangeEvent } from "react"; import { memo, useEffect, useId, useState } from "react"; import { toast } from "sonner"; import ThumbnailsShimmer from "@/components/Shared/Shimmer/ThumbnailsShimmer"; import { Spinner } from "@/components/Shared/UI"; import generateVideoThumbnails from "@/helpers/generateVideoThumbnails"; import getFileFromDataURL from "@/helpers/getFileFromDataURL"; import { uploadFileToIPFS } from "@/helpers/uploadToIPFS"; import { usePostAttachmentStore } from "@/store/non-persisted/post/usePostAttachmentStore"; import { usePostVideoStore } from "@/store/non-persisted/post/usePostVideoStore"; const DEFAULT_THUMBNAIL_INDEX = 0; export const THUMBNAIL_GENERATE_COUNT = 4; interface Thumbnail { blobUrl: string; decentralizedUrl: string; } const ChooseThumbnail = () => { const inputId = useId(); const [thumbnails, setThumbnails] = useState([]); const [imageUploading, setImageUploading] = useState(false); const [selectedThumbnailIndex, setSelectedThumbnailIndex] = useState(-1); const { attachments } = usePostAttachmentStore(); const { setVideoThumbnail, videoThumbnail } = usePostVideoStore(); const { file } = attachments[0]; const uploadThumbnailToStorageNode = async (fileToUpload: File) => { setVideoThumbnail({ ...videoThumbnail, uploading: true }); const result = await uploadFileToIPFS(fileToUpload); if (!result.uri) { toast.error("Failed to upload thumbnail"); } setVideoThumbnail({ mimeType: fileToUpload.type || "image/jpeg", uploading: false, url: result.uri }); return result; }; const handleSelectThumbnail = (index: number) => { setSelectedThumbnailIndex(index); if (thumbnails[index]?.decentralizedUrl === "") { setVideoThumbnail({ ...videoThumbnail, uploading: true }); getFileFromDataURL( thumbnails[index].blobUrl, "thumbnail.jpeg", async (file: File) => { const result = await uploadThumbnailToStorageNode(file); setThumbnails( thumbnails.map((thumbnail, i) => { if (i === index) { thumbnail.decentralizedUrl = result.uri; } return thumbnail; }) ); } ); } else { setVideoThumbnail({ ...videoThumbnail, uploading: false, url: thumbnails[index]?.decentralizedUrl }); } }; const generateThumbnails = async (fileToGenerate: File) => { try { const thumbnailArray = await generateVideoThumbnails( fileToGenerate, THUMBNAIL_GENERATE_COUNT ); const thumbnailList: Thumbnail[] = []; for (const thumbnailBlob of thumbnailArray) { thumbnailList.push({ blobUrl: thumbnailBlob, decentralizedUrl: "" }); } setThumbnails(thumbnailList); setSelectedThumbnailIndex(DEFAULT_THUMBNAIL_INDEX); } catch {} }; useEffect(() => { handleSelectThumbnail(selectedThumbnailIndex); }, [selectedThumbnailIndex]); useEffect(() => { if (file) { generateThumbnails(file); } return () => { setSelectedThumbnailIndex(-1); setThumbnails([]); }; }, [file]); const handleUpload = async (event: ChangeEvent) => { if (event.target.files?.length) { try { setImageUploading(true); setSelectedThumbnailIndex(-1); const file = event.target.files[0]; const result = await uploadThumbnailToStorageNode(file); const preview = window.URL?.createObjectURL(file); setThumbnails([ { blobUrl: preview, decentralizedUrl: result.uri }, ...thumbnails ]); setSelectedThumbnailIndex(0); } catch { toast.error("Failed to upload thumbnail"); } finally { setImageUploading(false); } } }; const isUploading = videoThumbnail.uploading; return (
Choose Thumbnail
{thumbnails.length ? null : } {thumbnails.map(({ blobUrl, decentralizedUrl }, index) => { const isSelected = selectedThumbnailIndex === index; const isUploaded = decentralizedUrl === videoThumbnail.url; return ( ); })}
); }; export default memo(ChooseThumbnail);