Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 95 lines 2.9 kB view raw
1import { PhotoIcon } from "@heroicons/react/24/outline"; 2import { TRANSFORMS } from "@hey/data/constants"; 3import imageKit from "@hey/helpers/imageKit"; 4import sanitizeDStorageUrl from "@hey/helpers/sanitizeDStorageUrl"; 5import type { ApolloClientError } from "@hey/types/errors"; 6import type { ChangeEvent, Ref } from "react"; 7import { useCallback, useState } from "react"; 8import { Image, Spinner } from "@/components/Shared/UI"; 9import cn from "@/helpers/cn"; 10import errorToast from "@/helpers/errorToast"; 11import { uploadFileToIPFS } from "@/helpers/uploadToIPFS"; 12 13interface CoverImageProps { 14 cover: string; 15 imageRef: Ref<HTMLImageElement>; 16 isNew: boolean; 17 setCover: (previewUri: string, url: string, mimeType: string) => void; 18} 19 20const CoverImage = ({ 21 cover, 22 imageRef, 23 isNew = false, 24 setCover 25}: CoverImageProps) => { 26 const [isSubmitting, setIsSubmitting] = useState(false); 27 28 const onError = useCallback((error: ApolloClientError) => { 29 setIsSubmitting(false); 30 errorToast(error); 31 }, []); 32 33 const onChange = async (event: ChangeEvent<HTMLInputElement>) => { 34 if (event.target.files?.length) { 35 try { 36 setIsSubmitting(true); 37 const file = event.target.files[0]; 38 const attachment = await uploadFileToIPFS(file); 39 setCover( 40 URL.createObjectURL(file), 41 attachment.uri, 42 file.type || "image/jpeg" 43 ); 44 } catch (error) { 45 onError(error); 46 } 47 } 48 }; 49 50 return ( 51 <div className="group relative flex-none overflow-hidden"> 52 <button className="flex focus:outline-hidden" type="button"> 53 <Image 54 alt={`attachment-audio-cover-${cover}`} 55 className="size-24 rounded-xl object-cover md:size-40 md:rounded-none" 56 draggable={false} 57 onError={({ currentTarget }) => { 58 currentTarget.src = cover ? sanitizeDStorageUrl(cover) : cover; 59 }} 60 ref={imageRef} 61 src={ 62 cover 63 ? imageKit(sanitizeDStorageUrl(cover), TRANSFORMS.ATTACHMENT) 64 : cover 65 } 66 /> 67 </button> 68 {isNew && ( 69 <label 70 className={cn( 71 { invisible: cover, visible: isSubmitting && !cover }, 72 "absolute top-0 grid size-24 cursor-pointer place-items-center bg-gray-100 backdrop-blur-lg group-hover:visible md:size-40 dark:bg-gray-900" 73 )} 74 > 75 {isSubmitting && !cover ? ( 76 <Spinner size="sm" /> 77 ) : ( 78 <div className="flex flex-col items-center text-sm opacity-60"> 79 <PhotoIcon className="size-5" /> 80 <span>Add cover</span> 81 </div> 82 )} 83 <input 84 accept=".png, .jpg, .jpeg, .svg" 85 className="hidden w-full" 86 onChange={onChange} 87 type="file" 88 /> 89 </label> 90 )} 91 </div> 92 ); 93}; 94 95export default CoverImage;