import React, { useEffect, useRef, useState } from "react"; import styled from "styled-components"; import Button, { Category, Size } from "./Button"; import { ReactComponent as UploadIcon } from "../../assets/icons/ads/upload-v2.svg"; import { ReactComponent as UploadSuccessIcon } from "../../assets/icons/ads/upload_success.svg"; import { DndProvider, useDrop, DropTargetMonitor } from "react-dnd"; import HTML5Backend, { NativeTypes } from "react-dnd-html5-backend"; import Text, { TextType } from "./Text"; import { Variant } from "./common"; import { Toaster } from "./Toast"; import { createMessage, ERROR_FILE_TOO_LARGE, REMOVE_FILE_TOOL_TIP, } from "@appsmith/constants/messages"; import TooltipComponent from "components/ads/Tooltip"; import { Position } from "@blueprintjs/core/lib/esm/common/position"; import Icon, { IconSize } from "./Icon"; import { ContainerDiv, FileEndings, FileType, FilePickerProps, } from "./FilePicker"; const ContainerDivWithBorder = styled(ContainerDiv)<{ isUploaded: boolean; isActive: boolean; canDrop: boolean; fileType: FileType; }>` width: 100%; height: 188px; background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' stroke='%23F86A2B' stroke-width='1.2' stroke-dasharray='6.4%2c 6.4' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e"); background-color: ${(props) => props.theme.colors.homepageBackground}; `; const IconWrapper = styled.div` width: ${(props) => props.theme.spaces[9]}px; padding-left: ${(props) => props.theme.spaces[2]}px; `; function FilePickerComponent(props: FilePickerProps) { const { fileType, logoUploadError } = props; const [fileInfo, setFileInfo] = useState<{ name: string; size: number }>({ name: "", size: 0, }); const [isUploaded, setIsUploaded] = useState(false); const [fileUrl, setFileUrl] = useState(""); const [{ canDrop, isOver }, drop] = useDrop({ accept: [NativeTypes.FILE], drop(item, monitor) { onDrop(monitor); }, collect: (monitor) => ({ isOver: monitor.isOver(), canDrop: monitor.canDrop(), }), }); const inputRef = useRef(null); const bgRef = useRef(null); const progressRef = useRef(null); const fileDescRef = useRef(null); const fileContainerRef = useRef(null); function ButtonClick(event: React.MouseEvent) { event.preventDefault(); if (inputRef.current) { inputRef.current.click(); } } function onDrop(monitor: DropTargetMonitor) { if (monitor) { const files = monitor.getItem().files; if (!files) { return; } handleFileUpload(files); } } function setProgress(uploadPercentage: number) { if (progressRef.current) { progressRef.current.style.width = `${uploadPercentage}%`; } if (uploadPercentage === 100) { setIsUploaded(true); if (fileDescRef.current && bgRef.current && fileType === FileType.IMAGE) { fileDescRef.current.style.display = "none"; bgRef.current.style.opacity = "1"; } } } function onUpload(url: string) { props.onFileUploaded && props.onFileUploaded(url); } function handleFileUpload(files: FileList | null) { if (fileType === FileType.IMAGE) { handleImageFileUpload(files); } else { handleOtherFileUpload(files); } } function handleOtherFileUpload(files: FileList | null) { const file = files && files[0]; let fileSize = 0; if (!file) { return; } fileSize = Math.floor(file.size / 1024); setFileInfo({ name: file.name, size: fileSize }); if (props.delayedUpload) { setIsUploaded(true); setProgress(100); } if (fileDescRef.current) { fileDescRef.current.style.display = "flex"; } if (fileContainerRef.current) { fileContainerRef.current.style.display = "none"; } props.fileUploader && props.fileUploader(file, setProgress, onUpload); } function handleImageFileUpload(files: FileList | null) { const file = files && files[0]; let fileSize = 0; if (!file) { return; } fileSize = Math.floor(file.size / 1024); setFileInfo({ name: file.name, size: fileSize }); if (fileSize < 250) { if (bgRef.current) { bgRef.current.style.backgroundImage = `url(${URL.createObjectURL( file, )})`; bgRef.current.style.opacity = "0.5"; } if (fileDescRef.current) { fileDescRef.current.style.display = "block"; } if (fileContainerRef.current) { fileContainerRef.current.style.display = "none"; } /* set form data and send api request */ props.fileUploader && props.fileUploader(file, setProgress, onUpload); } else { Toaster.show({ text: createMessage(ERROR_FILE_TOO_LARGE, "250 KB"), variant: Variant.warning, }); } } function removeFile() { if (fileContainerRef.current) { setFileUrl(""); if (fileDescRef.current) { fileDescRef.current.style.display = "none"; } fileContainerRef.current.style.display = "flex"; if (bgRef.current) { bgRef.current.style.backgroundImage = "url('')"; } setIsUploaded(false); props.onFileRemoved && props.onFileRemoved(); } } const isActive = canDrop && isOver; useEffect(() => { if (props.url) { const urlKeys = props.url.split("/"); if (urlKeys[urlKeys.length - 1] !== "null") { setFileUrl(props.url); } else { setFileUrl(""); } } }, [props.url]); // Following hook should be used only if file type is image. useEffect(() => { if (fileUrl && !isUploaded && fileType === FileType.IMAGE) { setIsUploaded(true); if (bgRef.current) { bgRef.current.style.backgroundImage = `url(${fileUrl})`; bgRef.current.style.opacity = "1"; } if (fileDescRef.current) { fileDescRef.current.style.display = "none"; } if (fileContainerRef.current) { fileContainerRef.current.style.display = "none"; } } }, [fileUrl, logoUploadError]); // const uploadFileForm = (
Drag & Drop files to upload or
handleFileUpload(el.target.files)} ref={inputRef} type="file" value={""} />
); const uploadStatus = (
{fileInfo.name} {fileInfo.size}KB
); const imageUploadComponent = ( <>
{uploadFileForm}
{uploadStatus}
); const uploadComponent = (
{uploadFileForm}
{uploadStatus}
Successfully Uploaded! removeFile()}>
); return ( {fileType === FileType.IMAGE ? imageUploadComponent : uploadComponent} ); } function FilePickerV2(props: FilePickerProps) { return ( ); } export default FilePickerV2;