import { forwardRef, useCallback, useMemo, useRef, useState } from 'react'; import { motion } from 'framer-motion'; import PropTypes from 'prop-types'; import { clsm, noop } from '../../../../utils'; import { createAnimationProps } from '../../../../helpers/animationPropsHelper'; import { dashboard as $content } from '../../../../content'; import { Delete, Upload } from '../../../../assets/icons'; import { MAXIMUM_IMAGE_FILE_SIZE, SUPPORTED_IMAGE_FILE_FORMATS } from '../../../../constants'; import { useModal } from '../../../../contexts/Modal'; import Button from '../../../../components/Button'; import NoImageSrcIcon from '../../../../components/IconSelect/NoImageSrcIcon'; import Spinner from '../../../../components/Spinner'; import useImageUpload from '../../../../hooks/useImageUpload'; import useResize from '../../../../hooks/useResize'; const $channelAssetModalContent = $content.modal.channel_asset_deletion_modal; const STACKING_BREAKPOINT = 910; // px const isStackingBreakpoint = () => window.innerWidth < STACKING_BREAKPOINT; const ImageUploader = forwardRef( ( { assetType, className, onDelete, onImageDownload, onUpload, previewShape, shouldAnimate, uploadUrl }, containerRef ) => { const maximumFileSize = MAXIMUM_IMAGE_FILE_SIZE[assetType]; const { deleteChannelAsset, isDeleting, isDownloading, isUploading, setIsDownloading, uploadChannelAsset } = useImageUpload({ assetType, onDelete, onUpload, maximumFileSize }); const { openModal } = useModal(); const [shouldStack, setShouldStack] = useState(isStackingBreakpoint()); const fileInputRef = useRef(); const deleteButtonRef = useRef(); const hasUploadUrl = !!uploadUrl; const isLoadingNewImage = isUploading || isDownloading; const acceptedImageFileFormats = SUPPORTED_IMAGE_FILE_FORMATS.flat() .map((fileFormat) => `.${fileFormat}`) .join(','); const previewClasses = useMemo(() => { const classes = [ 'bg-lightMode-gray-extraLight', 'dark:bg-darkMode-gray', 'w-auto', shouldStack ? 'h-full' : `h-[124px]` ]; if (previewShape === 'round') return classes.concat(['aspect-square', 'rounded-full']); if (previewShape === '16/9') return classes.concat(['aspect-video', 'rounded-xl']); }, [previewShape, shouldStack]); useResize(useCallback(() => setShouldStack(isStackingBreakpoint()), [])); const handleUpload = async (e) => { await uploadChannelAsset(e); e.target.value = ''; }; const handleDelete = () => { const confirmText = $channelAssetModalContent.delete_image; const message = $channelAssetModalContent.confirm_intent_message.replace( '{ASSET_TYPE}', assetType ); openModal({ content: { confirmText, message, isDestructive: true }, onConfirm: deleteChannelAsset, lastFocusedElement: deleteButtonRef }); }; const handleImageFullyDownloaded = useCallback(() => { // This condition prevents `onImageDownload` to be called on the initial render if (isDownloading) { onImageDownload(); } setIsDownloading(false); }, [isDownloading, onImageDownload, setIsDownloading]); const renderPreview = useCallback(() => { if (isUploading || hasUploadUrl) { return ( <> {/* If the image is done being uploaded we want to also wait for the the image to completely download before replacing the spinner with the image tag. */} {hasUploadUrl && ( {`${assetType} )} {isLoadingNewImage && (
)} ); } else { return ( ); } }, [ assetType, handleImageFullyDownloaded, hasUploadUrl, isLoadingNewImage, isUploading, previewClasses, previewShape, uploadUrl ]); return (
{renderPreview()}

{$content.settings_page.upload_restrictions .replace( '{FILE_FORMATS}', SUPPORTED_IMAGE_FILE_FORMATS.map((fileFormat) => (typeof fileFormat === 'string' ? fileFormat : fileFormat[0] ).toUpperCase() ).join(', ') ) .replace('{MAXIMUM_FILE_SIZE}', maximumFileSize)}

); } ); ImageUploader.propTypes = { assetType: PropTypes.string.isRequired, className: PropTypes.string, onDelete: PropTypes.func, onImageDownload: PropTypes.func, onUpload: PropTypes.func, previewShape: PropTypes.oneOf(['round', '16/9']), shouldAnimate: PropTypes.bool, uploadUrl: PropTypes.string }; ImageUploader.defaultProps = { className: '', onDelete: noop, onImageDownload: noop, onUpload: noop, previewShape: 'round', shouldAnimate: true, uploadUrl: '' }; export default ImageUploader;