2020-03-10 13:36:21 +00:00
|
|
|
import React, { useState, useContext, useEffect } from "react";
|
2020-02-18 16:25:03 +00:00
|
|
|
import classNames from "classnames";
|
2020-03-10 13:36:21 +00:00
|
|
|
import path from "path-browserify";
|
|
|
|
import { useDropzone } from "react-dropzone";
|
2020-02-18 16:25:03 +00:00
|
|
|
import Reveal from "react-reveal/Reveal";
|
|
|
|
import { Button, UploadFile } from "../";
|
|
|
|
import { Deco3, Deco4, Deco5, Folder, DownArrow } from "../../svg";
|
|
|
|
import "./HomeUpload.scss";
|
2020-02-28 12:52:32 +00:00
|
|
|
import AppContext from "../../AppContext";
|
2020-03-10 13:15:34 +00:00
|
|
|
import axios from "axios";
|
2020-02-12 17:23:10 +00:00
|
|
|
|
2020-02-27 11:16:05 +00:00
|
|
|
export default function HomeUpload() {
|
|
|
|
const [files, setFiles] = useState([]);
|
2020-02-28 12:52:32 +00:00
|
|
|
const { apiUrl } = useContext(AppContext);
|
2020-03-10 13:36:21 +00:00
|
|
|
const [directoryMode, setDirectoryMode] = useState(false);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (directoryMode) {
|
|
|
|
inputRef.current.setAttribute("webkitdirectory", "true");
|
|
|
|
} else {
|
|
|
|
inputRef.current.removeAttribute("webkitdirectory");
|
|
|
|
}
|
|
|
|
}, [directoryMode]);
|
|
|
|
|
|
|
|
const getFilePath = (file) => file.webkitRelativePath || file.path || file.name;
|
|
|
|
|
|
|
|
const getRelativeFilePath = (file) => {
|
|
|
|
const filePath = getFilePath(file);
|
|
|
|
const { root, dir, base } = path.parse(filePath);
|
|
|
|
const relative = path
|
|
|
|
.normalize(dir)
|
|
|
|
.slice(root.length)
|
|
|
|
.split(path.sep)
|
|
|
|
.slice(1);
|
|
|
|
|
|
|
|
return path.join(...relative, base);
|
|
|
|
};
|
|
|
|
|
|
|
|
const getRootDirectory = (file) => {
|
|
|
|
const filePath = getFilePath(file);
|
|
|
|
const { root, dir } = path.parse(filePath);
|
|
|
|
|
|
|
|
return path
|
|
|
|
.normalize(dir)
|
|
|
|
.slice(root.length)
|
|
|
|
.split(path.sep)[0];
|
|
|
|
};
|
2020-02-12 17:23:10 +00:00
|
|
|
|
2020-02-28 16:19:33 +00:00
|
|
|
const handleDrop = async (acceptedFiles) => {
|
2020-03-10 13:36:21 +00:00
|
|
|
if (directoryMode && acceptedFiles.length) {
|
|
|
|
const rootDir = getRootDirectory(acceptedFiles[0]); // get the file path from the first file
|
|
|
|
|
|
|
|
acceptedFiles = [{ name: rootDir, directory: true, files: acceptedFiles }];
|
|
|
|
}
|
|
|
|
|
2020-02-28 16:19:33 +00:00
|
|
|
setFiles((previousFiles) => [...acceptedFiles.map((file) => ({ file, status: "uploading" })), ...previousFiles]);
|
2020-02-12 17:23:10 +00:00
|
|
|
|
2020-03-10 13:15:34 +00:00
|
|
|
const onFileStateChange = (file, state) => {
|
2020-02-28 16:19:33 +00:00
|
|
|
setFiles((previousFiles) => {
|
|
|
|
const index = previousFiles.findIndex((f) => f.file === file);
|
2020-02-27 11:16:05 +00:00
|
|
|
|
|
|
|
return [
|
|
|
|
...previousFiles.slice(0, index),
|
|
|
|
{
|
|
|
|
...previousFiles[index],
|
2020-03-10 13:15:34 +00:00
|
|
|
...state
|
2020-02-27 11:16:05 +00:00
|
|
|
},
|
|
|
|
...previousFiles.slice(index + 1)
|
|
|
|
];
|
2020-02-18 16:25:03 +00:00
|
|
|
});
|
|
|
|
};
|
2020-02-12 17:23:10 +00:00
|
|
|
|
2020-03-10 13:36:21 +00:00
|
|
|
const upload = async (formData, directory, file) => {
|
|
|
|
const uploadUrl = `${apiUrl}/skynet/skyfile/${directory ? `?filename=${encodeURIComponent(directory)}` : ""}`;
|
|
|
|
const { data } = await axios.post(uploadUrl, formData, {
|
|
|
|
onUploadProgress: ({ loaded, total }) => {
|
|
|
|
const progress = loaded / total;
|
|
|
|
const status = progress === 1 ? "processing" : "uploading";
|
|
|
|
|
|
|
|
onFileStateChange(file, { status, progress });
|
|
|
|
}
|
|
|
|
});
|
2020-03-10 13:15:34 +00:00
|
|
|
|
2020-03-10 13:36:21 +00:00
|
|
|
return data;
|
2020-03-10 13:15:34 +00:00
|
|
|
};
|
|
|
|
|
2020-02-28 16:19:33 +00:00
|
|
|
acceptedFiles.forEach(async (file) => {
|
2020-02-12 17:23:10 +00:00
|
|
|
try {
|
2020-03-10 13:36:21 +00:00
|
|
|
const formData = new FormData();
|
|
|
|
|
|
|
|
if (file.directory) {
|
|
|
|
file.files.forEach((directoryFile) => {
|
|
|
|
const relativeFilePath = getRelativeFilePath(directoryFile);
|
2020-02-18 06:01:36 +00:00
|
|
|
|
2020-03-10 13:36:21 +00:00
|
|
|
formData.append("files[]", directoryFile, relativeFilePath);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
formData.append("file", file);
|
|
|
|
}
|
2020-02-12 17:23:10 +00:00
|
|
|
|
2020-03-10 13:36:21 +00:00
|
|
|
const { skylink } = await upload(formData, directoryMode && file.name, file);
|
|
|
|
|
|
|
|
onFileStateChange(file, { status: "complete", url: `${apiUrl}/${skylink}` });
|
2020-02-12 22:13:34 +00:00
|
|
|
} catch (error) {
|
2020-03-10 13:15:34 +00:00
|
|
|
onFileStateChange(file, { status: "error" });
|
2020-02-12 17:23:10 +00:00
|
|
|
}
|
2020-02-18 16:25:03 +00:00
|
|
|
});
|
|
|
|
};
|
2020-02-12 17:23:10 +00:00
|
|
|
|
2020-03-10 13:36:21 +00:00
|
|
|
const { getRootProps, getInputProps, isDragActive, inputRef } = useDropzone({ onDrop: handleDrop });
|
|
|
|
|
2020-02-28 16:19:33 +00:00
|
|
|
const handleSkylink = (event) => {
|
2020-02-18 16:25:03 +00:00
|
|
|
event.preventDefault();
|
2020-02-13 23:30:36 +00:00
|
|
|
|
2020-02-18 16:25:03 +00:00
|
|
|
const skylink = event.target.skylink.value.replace("sia://", "");
|
2020-02-13 23:30:36 +00:00
|
|
|
|
2020-02-14 02:51:37 +00:00
|
|
|
if (skylink.match(/^[a-zA-Z0-9_-]{46}$/)) {
|
2020-02-18 16:25:03 +00:00
|
|
|
window.open(skylink, "_blank");
|
2020-02-13 23:30:36 +00:00
|
|
|
}
|
2020-02-18 16:25:03 +00:00
|
|
|
};
|
2020-02-13 23:30:36 +00:00
|
|
|
|
2020-02-27 11:16:05 +00:00
|
|
|
return (
|
|
|
|
<Reveal effect="active">
|
|
|
|
<div className="home-upload">
|
|
|
|
<div className="home-upload-white fadeInUp delay4">
|
|
|
|
<div className="home-upload-split">
|
|
|
|
<div className="home-upload-box ">
|
2020-03-10 13:36:21 +00:00
|
|
|
<div
|
|
|
|
className={classNames("home-upload-dropzone", {
|
|
|
|
"drop-active": isDragActive
|
|
|
|
})}
|
|
|
|
{...getRootProps()}
|
|
|
|
>
|
|
|
|
<span className="home-upload-text">
|
|
|
|
<h3>Upload your {directoryMode ? "Directory" : "Files"}</h3>
|
|
|
|
Drop your {directoryMode ? "directory" : "files"} here to pin to Skynet
|
|
|
|
</span>
|
|
|
|
<Button iconLeft>
|
|
|
|
<Folder />
|
|
|
|
Browse
|
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
<input {...getInputProps()} className="offscreen" />
|
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
className="home-upload-mode-switch link"
|
|
|
|
onClick={() => setDirectoryMode(!directoryMode)}
|
|
|
|
>
|
|
|
|
{directoryMode ? "⇐ Switch back to uploading files" : "Do you want to upload entire directory?"}
|
|
|
|
</button>
|
|
|
|
{directoryMode && (
|
|
|
|
<p className="home-upload-directory-mode-notice">
|
|
|
|
Please note that directory upload is not a standard browser feature and the browser support is
|
|
|
|
limited. To check whether your browser is compatible, visit{" "}
|
|
|
|
<a
|
|
|
|
href="https://caniuse.com/#feat=mdn-api_htmlinputelement_webkitdirectory"
|
|
|
|
target="_blank"
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
className="link"
|
|
|
|
>
|
|
|
|
caniuse.com
|
|
|
|
</a>
|
|
|
|
.
|
|
|
|
</p>
|
|
|
|
)}
|
2020-02-13 22:07:42 +00:00
|
|
|
</div>
|
2020-02-14 02:51:37 +00:00
|
|
|
|
2020-02-27 11:16:05 +00:00
|
|
|
<div className="home-upload-retrieve">
|
|
|
|
<div className="home-upload-text">
|
|
|
|
<h3 id="skylink-retrieve-title">Have a Skylink?</h3>
|
|
|
|
<p>Paste the link to retrieve your file</p>
|
|
|
|
|
|
|
|
<form className="home-upload-retrieve-form" onSubmit={handleSkylink}>
|
|
|
|
<input name="skylink" type="text" placeholder="sia://" aria-labelledby="skylink-retrieve-title" />
|
|
|
|
<button type="submit" aria-label="Retrieve file">
|
|
|
|
<DownArrow />
|
|
|
|
</button>
|
|
|
|
</form>
|
2020-02-14 02:51:37 +00:00
|
|
|
</div>
|
2020-02-27 11:16:05 +00:00
|
|
|
</div>
|
2020-02-12 17:23:10 +00:00
|
|
|
</div>
|
|
|
|
|
2020-02-27 11:16:05 +00:00
|
|
|
{files.length > 0 && (
|
|
|
|
<div className="home-uploaded-files">
|
|
|
|
{files.map((file, i) => {
|
|
|
|
return <UploadFile key={i} {...file} />;
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
)}
|
2020-02-12 17:23:10 +00:00
|
|
|
</div>
|
2020-02-27 11:16:05 +00:00
|
|
|
|
|
|
|
<p className="bottom-text fadeInUp delay5">
|
|
|
|
Upon uploading a file, Skynet generates a 46 byte link called a <strong>Skylink</strong>. This link can then
|
|
|
|
be shared with anyone to retrieve the file on any Skynet Webportal.
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<Deco3 className="deco-3 fadeInUp delay6" />
|
|
|
|
<Deco4 className="deco-4 fadeInUp delay6" />
|
|
|
|
<Deco5 className="deco-5 fadeInUp delay6" />
|
|
|
|
</div>
|
|
|
|
</Reveal>
|
|
|
|
);
|
2020-02-12 17:23:10 +00:00
|
|
|
}
|