import React, { ReactNode, useContext, useEffect, useState } from 'react'; import { Box, useTheme } from '@mui/material'; import Typography from '@mui/material/Typography'; import InputHeader from '../InputHeader'; import InputFooter from './InputFooter'; import { BaseFileInputProps, createObjectURL, revokeObjectURL } from './file-input-utils'; import { globalInputHeight } from '../../config/uiConfig'; import { CustomSnackBarContext } from '../../contexts/CustomSnackBarContext'; import greyPattern from '@assets/grey-pattern.png'; import { isArray } from 'lodash'; interface BaseFileInputComponentProps extends BaseFileInputProps { children: (props: { preview: string | undefined }) => ReactNode; type: 'image' | 'video' | 'audio' | 'pdf'; } export default function BaseFileInput({ value, onChange, accept, title, children, type }: BaseFileInputComponentProps) { const [preview, setPreview] = useState(null); const [isDragging, setIsDragging] = useState(false); const theme = useTheme(); const fileInputRef = React.useRef(null); const { showSnackBar } = useContext(CustomSnackBarContext); useEffect(() => { if (value) { try { const objectUrl = createObjectURL(value); setPreview(objectUrl); return () => revokeObjectURL(objectUrl); } catch (error) { console.error('Error previewing file:', error); } } }, [value]); const handleFileChange = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) onChange(file); }; const handleImportClick = () => { fileInputRef.current?.click(); }; const handleCopy = () => { if (isArray(value)) { const blob = new Blob([value[0]], { type: value[0].type }); const clipboardItem = new ClipboardItem({ [value[0].type]: blob }); navigator.clipboard .write([clipboardItem]) .then(() => showSnackBar('File copied', 'success')) .catch((err) => { showSnackBar('Failed to copy: ' + err, 'error'); }); } }; function handleClear() { // @ts-ignore onChange(null); } const handleDrop = (event: React.DragEvent) => { event.preventDefault(); event.stopPropagation(); setIsDragging(false); if (event.dataTransfer.files && event.dataTransfer.files.length > 0) { const file = event.dataTransfer.files[0]; // Check if file type is acceptable const isAcceptable = accept.some((acceptType) => { // Handle wildcards like "image/*" if (acceptType.endsWith('/*')) { const category = acceptType.split('/')[0]; return file.type.startsWith(category); } return acceptType === file.type; }); if (isAcceptable) { onChange(file); } else { showSnackBar( `Invalid file type. Please use ${accept.join(', ')}`, 'error' ); } } }; const handleDragOver = (event: React.DragEvent) => { event.preventDefault(); event.stopPropagation(); }; const handleDragEnter = (event: React.DragEvent) => { event.preventDefault(); event.stopPropagation(); setIsDragging(true); }; const handleDragLeave = (event: React.DragEvent) => { event.preventDefault(); event.stopPropagation(); setIsDragging(false); }; useEffect(() => { const handlePaste = (event: ClipboardEvent) => { const clipboardItems = event.clipboardData?.items ?? []; const item = clipboardItems[0]; if ( item && (item.type.includes('image') || item.type.includes('video')) ) { const file = item.getAsFile(); if (file) onChange(file); } }; window.addEventListener('paste', handlePaste); return () => { window.removeEventListener('paste', handlePaste); }; }, [onChange]); return ( {preview ? ( {children({ preview })} ) : ( {isDragging ? ( Drop your {type} here ) : ( Click here to select a {type} from your device, press Ctrl+V to use a {type} from your clipboard, or drag and drop a file from desktop )} )} ); }