1
0
forked from YaBL/app
app/apps/web/src/pages/account/UploadBook.jsx
2025-06-21 12:42:09 +03:00

141 lines
4.6 KiB
JavaScript

import { useEffect, useRef, useState } from "react";
import FilledButton from "../../md-components/FilledButton";
import Icon from "../../md-components/Icon";
import IconButton from "../../md-components/IconButton";
import axios from "axios";
import { toast } from "react-toastify";
function UploadBook() {
const fileSelectorRef = useRef();
const [uploadedFiles, setUploadedFiles] = useState([]);
const [uploadStatuses, setUploadStatuses] = useState([]);
const [isDragging, setIsDragging] = useState(false);
const [uploading, setUploading] = useState(false);
const handleFileChange = (e) => {
const files = Array.from(e.target.files);
setUploadedFiles((prev) => [...prev, ...files]);
};
const handleDrop = (e) => {
e.preventDefault();
setIsDragging(false);
const droppedFiles = Array.from(e.dataTransfer.files);
setUploadedFiles((prev) => [...prev, ...droppedFiles]);
};
const handleDragOver = (e) => {
e.preventDefault();
setIsDragging(true);
};
const handleDragLeave = () => {
setIsDragging(false);
};
useEffect(
() => setUploadStatuses(uploadedFiles.map(() => 0)),
[uploadedFiles]
);
const handleUpload = async () => {
setUploading(true);
console.log(uploading);
if (uploadedFiles.length === 0) {
alert("Нечего грузить, капитан.");
return;
}
for (const [i, file] of uploadedFiles.entries()) {
const formData = new FormData();
formData.append("files", file);
try {
console.log(uploadedFiles);
const res = await axios.post("/book/upload", formData);
console.log(res);
if (res.status === 200) {
// toast("Залили! 🧃");
setUploadStatuses((prev) => ({ ...prev, [i]: 1 }));
console.log(uploadStatuses);
} else {
toast("Ошибка на сервере, go дебажить.");
}
} catch (err) {
console.error("Ошибка:", err);
toast("Шатался интернет или сервер умер.");
}
}
setUploading(false);
setUploadedFiles([]);
};
if (!window.onLine) {
return <span>Недоступно оффлайн</span>;
}
return (
<div className="flex flex-col items-center justify-center h-screen">
<h1 className="text-2xl font-bold mb-4">Загрузка литературы</h1>
<div
className={`flex items-center justify-around w-full max-w-lg h-50 mb-4 rounded-xl flex-col gap-1 px-4 border-2 border-dashed transition-colors duration-200 cursor-pointer border-(--md-sys-color-outline) ${
isDragging
? "bg-(--md-sys-color-surface-variant)"
: "bg-(--md-sys-color-inverse-on-surface)"
}`}
onClick={() => fileSelectorRef.current.click()}
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
>
<>
<span className="font-bold">Перетащи файл сюда или кликни</span>
<IconButton className="w-24 h-24">
<Icon className="text-6xl w-24 h-24">upload_file</Icon>
</IconButton>
<span className="text-sm">Поддерживается .fb2 и .pdf</span>
</>
<input
type="file"
multiple
accept=".fb2,.pdf"
ref={fileSelectorRef}
className="hidden"
onChange={handleFileChange}
/>
</div>
<div className="w-full max-w-lg bg-(--md-sys-color-surface-variant) flex p-[18px] rounded-2xl flex-col max-h-60 overflow-scroll gap-3 mb-4">
{uploadedFiles.length === 0 ? <span>Нечего загружать</span> : <></>}
{uploadedFiles.map((file, i) => (
<div className="flex justify-between" key={i}>
<span className="truncate w-[calc(100%-42px)] inline-block">
{file.name}
</span>
{uploading ? (
<Icon className="text-(--md-sys-color-on-surface)">
{uploadStatuses[i] === 0
? "sync"
: uploadStatuses[i] === -1
? "error"
: "check_circle"}
</Icon>
) : (
<IconButton
onClick={() =>
setUploadedFiles((prev) => prev.filter((_, io) => io !== i))
}
>
<Icon>remove</Icon>
</IconButton>
)}
</div>
))}
</div>
<FilledButton onClick={handleUpload} disabled={uploading}>
Загрузить
</FilledButton>
</div>
);
}
export default UploadBook;