import { generateVideoThumbnails, getVideoDurationFromVideoFile, } from '@rajesh896/video-thumbnails-generator'; import { useCallback, useState } from 'react'; import { DropzoneOptions, useDropzone } from 'react-dropzone'; import { toast } from 'react-hot-toast'; import { fetcher } from '../utils'; import { SignedPayload } from '../types'; const useMediaUpload = ( onUpload: (uploadUrl: string) => void, options?: Partial, ) => { const [isUploading, setUploading] = useState(false); const upload = useCallback(async (file: File, chatId?: string) => { const { id, signedUrl, publicUrl, fields } = await fetcher( '/api/sign', { method: 'POST', body: JSON.stringify({ id: chatId, fileType: file.type, fileName: file.name, }), }, ); const formData = new FormData(); Object.entries(fields).forEach(([key, value]) => { formData.append(key, value as string); }); formData.append('file', file); const uploadResponse = await fetch(signedUrl, { method: 'POST', body: formData, }); if (!uploadResponse.ok) { toast.error(uploadResponse.statusText); return; } return { id, publicUrl, }; }, []); const { getRootProps, getInputProps, isDragActive, open } = useDropzone({ accept: { 'image/*': ['.jpeg', '.png'], 'video/mp4': ['.mp4', '.MP4'], }, noClick: true, noKeyboard: true, multiple: false, onDrop: async files => { if (files.length !== 1) { throw new Error('Only one image can be uploaded at a time'); } setUploading(true); const reader = new FileReader(); reader.readAsDataURL(files[0]); reader.onload = async () => { const file = files[0]; if (file.type === 'video/mp4') { const duration = await getVideoDurationFromVideoFile(file); if (duration > 30) { setUploading(false); toast.error('Video duration must be less than 30 seconds'); return; } } else if (file.size > 2.5 * 1024 * 1024) { setUploading(false); toast.error('Image size must be less than 2.5MB'); return; } const resp = await upload(file); if (!resp) { return; } if (file.type === 'video/mp4') { const thumbnails = await generateVideoThumbnails(file, 1, 'file'); fetch(thumbnails[0]) .then(res => res.blob()) .then(blob => { const thumbnailFile = new File( [blob], file.name.replace('.mp4', '.png').replace('.MP4', '.png'), { type: 'image/png', }, ); return upload(thumbnailFile, resp.id); }); } onUpload(resp.publicUrl); setUploading(false); }; }, ...options, }); return { getRootProps, getInputProps, isDragActive, isUploading, openUpload: open, }; }; export default useMediaUpload;