UNPKG

ar-design

Version:

AR Design is a (react | nextjs) ui library.

158 lines (157 loc) 8.06 kB
import React, { useEffect, useRef, useState } from "react"; import "../../../assets/css/components/form/upload/styles.css"; import Tooltip from "../../feedback/tooltip"; import { ARIcon } from "../../icons"; const Upload = ({ text, file, onChange, allowedTypes, maxSize, multiple }) => { // refs const _firstLoad = useRef(false); const _input = useRef(null); const _arUplaod = useRef(null); // refs -> File Data const _validationErrors = useRef([]); // states const [selectedFiles, setSelectedFiles] = useState([]); const [selectedFile, setSelectedFile] = useState(undefined); const [validationErrors, setValidationErrors] = useState([]); // methods const handleFileChange = (files) => { const _files = Array.from(files ?? []); if (multiple) { setSelectedFiles((prev) => { const previousFileNames = prev.map((f) => f.name); const newFiles = _files.filter((f) => !previousFileNames.includes(f.name)) ?? []; return [...prev, ...newFiles]; }); } else { setSelectedFile(_files[0]); } }; const handleFileRemove = (fileToRemove) => { if (multiple) { const dataTransfer = new DataTransfer(); setSelectedFiles((prev) => { const newList = prev.filter((x) => x.name !== fileToRemove.name); newList.forEach((file) => dataTransfer.items.add(file)); if (_input.current) _input.current.files = dataTransfer.files; return newList; }); } else { setSelectedFile(undefined); } }; const handleValidationFile = (file) => { const newErrors = []; if (allowedTypes) { if (!allowedTypes.includes(file.type)) { newErrors.push({ [file.name]: "Geçersiz dosya türü." }); _validationErrors.current.push(file.name); } } if (maxSize) { const _maxSize = maxSize * 1024 * 1024; // MB if (file.size > _maxSize) { newErrors.push({ [file.name]: "Dosya boyutu çok büyük." }); _validationErrors.current.push(file.name); } } setValidationErrors((prev) => [...prev, ...newErrors]); }; function handleFileToBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { if (reader.result && typeof reader.result === "string") { resolve(reader.result); } else { reject(new Error("Failed to read the file")); } }; reader.onerror = reject; reader.readAsDataURL(file); }); } // useEffects useEffect(() => { (async () => { const dataTransfer = new DataTransfer(); const fileFormData = new FormData(); setValidationErrors([]); _validationErrors.current = []; if (_input.current) { if (multiple) { // Seçilmiş olan dosyalar validasyona gönderiliyor. selectedFiles.forEach((f) => handleValidationFile(f)); const inValidFiles = Array.from(new Set(_validationErrors.current)); // Input içerisine dosyalar aktarılıyor. selectedFiles.forEach((f) => dataTransfer.items.add(f)); _input.current.files = dataTransfer.files; // Geçerli olan dosyalar alındı... const validFiles = [...selectedFiles.filter((x) => !inValidFiles.includes(x.name))]; validFiles.forEach((f) => fileFormData.append("file", f)); // Geçerli olan dosyalar base64'e dönüştürülüyor... const base64Array = await Promise.all(validFiles.map((validFile) => handleFileToBase64(validFile))); onChange(fileFormData, validFiles, base64Array, _validationErrors.current.length === 0); } else { if (selectedFile) { handleValidationFile(selectedFile); fileFormData.append("file", selectedFile); onChange(fileFormData, selectedFile, await handleFileToBase64(selectedFile)); // Input içerisine dosyalar aktarılıyor. dataTransfer.items.add(selectedFile); _input.current.files = dataTransfer.files; } } } })(); }, [selectedFiles, selectedFile]); useEffect(() => { if (_firstLoad.current) return; multiple ? setSelectedFiles(file) : setSelectedFile(file); _firstLoad.current = true; }, [file]); return (React.createElement("div", { ref: _arUplaod, className: "ar-upload" }, React.createElement("input", { ref: _input, type: "file", onChange: (event) => handleFileChange(event.target.files), multiple: multiple }), React.createElement("div", { className: "ar-upload-button" }, React.createElement("div", { className: "button", onClick: () => { if (_input.current) _input.current.click(); } }, React.createElement("div", { className: "information" }, React.createElement(ARIcon, { variant: "linear", icon: "Upload", stroke: "var(--gray-600)", fill: "transparent" }), React.createElement("div", { className: "properies" }, allowedTypes && (React.createElement("div", { className: "allow-types" }, allowedTypes?.map((allowedType) => allowedType.split("/")[1].toLocaleUpperCase()).join(", "))), maxSize && React.createElement("div", { className: "max-size" }, "up to ", maxSize, "MB"))), text && React.createElement("span", null, text)), React.createElement("div", { className: "ar-upload-files" }, multiple ? (React.createElement("ul", null, selectedFiles.map((selectedFile, index) => { let _className = []; const errorMessages = validationErrors .filter((error) => Object.keys(error).includes(selectedFile.name)) .map((error) => error[selectedFile.name]); if (errorMessages.length > 0) _className.push("error"); const content = (React.createElement("div", { className: "content" }, React.createElement("span", { className: _className.map((c) => c).join(" ") }, selectedFile.name), React.createElement("span", { onClick: (event) => { event.stopPropagation(); handleFileRemove(selectedFile); } }, "x"))); return (React.createElement("li", { key: index, className: _className.map((c) => c).join(" ") }, errorMessages.length === 0 ? (content) : (React.createElement(Tooltip, { text: errorMessages.map((message) => message ?? "") }, content)))); }))) : (selectedFile && (React.createElement("div", { className: "file" }, React.createElement("div", { className: "information" }, React.createElement("span", null, selectedFile.name), React.createElement("span", null, (selectedFile.size / 1024).toFixed(3), "KB")), React.createElement("div", { className: "delete", onClick: () => handleFileRemove(selectedFile) }, React.createElement(ARIcon, { icon: "CloseCircle", fill: "transparent", size: 20 }))))))))); }; export default Upload;