You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

396 lines
18 KiB

import UploadFile from "../../components/Modals/ManageWorkspace/Documents/UploadFile";
import PreLoader from "@/components/Preloader";
import { memo, useEffect, useState } from "react";
import FolderRow from "../../components/Modals/ManageWorkspace/Documents/Directory/FileRow";
import System from "@/models/system";
import { MagnifyingGlass, Plus, Trash } from "@phosphor-icons/react";
import Document from "@/models/document";
import showToast from "@/utils/toast";
import FolderSelectionPopup from "../../components/Modals/ManageWorkspace/Documents/Directory/FolderSelectionPopup";
import MoveToFolderIcon from "../../components/Modals/ManageWorkspace/Documents/Directory/MoveToFolderIcon";
import { useModal } from "@/hooks/useModal";
import NewFolderModal from "../../components/Modals/ManageWorkspace/Documents/Directory/NewFolderModal";
import debounce from "lodash.debounce";
import { filterFileSearchResults } from "../../components/Modals/ManageWorkspace/Documents/Directory/utils";
// import ContextMenu from "../../components/Modals/ManageWorkspace/Documents/Directory/ContextMenu";
import { Tooltip } from "react-tooltip";
import { safeJsonParse } from "@/utils/request";
import { data } from "autoprefixer";
function Directory({
files,
setFiles,
loading,
setLoading,
workspace,
fetchKeys,
selectedItems,
setSelectedItems,
setHighlightWorkspace,
moveToWorkspace,
setLoadingMessage,
loadingMessage,
}) {
const [amountSelected, setAmountSelected] = useState(0);
const [showFolderSelection, setShowFolderSelection] = useState(false);
const [searchTerm, setSearchTerm] = useState("");
const [dataTo, setFDataTo] = useState([]);
const [show, setShow] = useState(false);
const {
isOpen: isFolderModalOpen,
openModal: openFolderModal,
closeModal: closeFolderModal,
} = useModal();
// const [contextMenu, setContextMenu] = useState({
// visible: false,
// x: 0,
// y: 0,
// });
useEffect(() => {
async function fetchUsers() {
const nodata = await System.localFiles();
const em0 = nodata.items[0].items
const em1 = nodata.items[1].items
const em2 = nodata.items[2].items
const em = [...em0,...em1,...em2]
setFDataTo(em)
console.log(2222,nodata);
}
fetchUsers();
}, []);
const deleteFiles = async (event) => {
event.stopPropagation();
if (
!window.confirm(
"Are you sure you want to delete these files and folders?\nThis will remove the files from the system and remove them from any existing workspaces automatically.\nThis action is not reversible."
)
) {
return false;
}
try {
const toRemove = [];
const foldersToRemove = [];
for (const itemId of Object.keys(selectedItems)) {
for (const folder of files.items) {
const foundItem = folder.items.find((file) => file.id === itemId);
if (foundItem) {
toRemove.push(`${folder.name}/${foundItem.name}`);
break;
}
}
}
for (const folder of files.items) {
if (folder.name === "custom-documents") {
continue;
}
if (isSelected(folder.id, folder)) {
foldersToRemove.push(folder.name);
}
}
setLoading(true);
setLoadingMessage(
`Removing ${toRemove.length} documents and ${foldersToRemove.length} folders. Please wait.`
);
await System.deleteDocuments(toRemove);
for (const folderName of foldersToRemove) {
await System.deleteFolder(folderName);
}
await fetchKeys(true);
setSelectedItems({});
} catch (error) {
console.error("Failed to delete files and folders:", error);
} finally {
setLoading(false);
setSelectedItems({});
}
};
const toggleSelection = (item) => {
setSelectedItems((prevSelectedItems) => {
const newSelectedItems = { ...prevSelectedItems };
if (item.type === "folder") {
// select all files in the folder
if (newSelectedItems[item.name]) {
delete newSelectedItems[item.name];
item.items.forEach((file) => delete newSelectedItems[file.id]);
} else {
newSelectedItems[item.name] = true;
item.items.forEach((file) => (newSelectedItems[file.id] = true));
}
} else {
// single file selections
if (newSelectedItems[item.id]) {
delete newSelectedItems[item.id];
} else {
newSelectedItems[item.id] = true;
}
}
return newSelectedItems;
});
};
// check if item is selected based on selectedItems state
const isSelected = (id, item) => {
if (item && item.type === "folder") {
if (!selectedItems[item.name]) {
return false;
}
return item.items.every((file) => selectedItems[file.id]);
}
return !!selectedItems[id];
};
const moveToFolder = async (folder) => {
const toMove = [];
for (const itemId of Object.keys(selectedItems)) {
for (const currentFolder of files.items) {
const foundItem = currentFolder.items.find(
(file) => file.id === itemId
);
if (foundItem) {
toMove.push({ ...foundItem, folderName: currentFolder.name });
break;
}
}
}
setLoading(true);
setLoadingMessage(`Moving ${toMove.length} documents. Please wait.`);
const { success, message } = await Document.moveToFolder(
toMove,
folder.name
);
if (!success) {
showToast(`Error moving files: ${message}`, "error");
setLoading(false);
return;
}
if (success && message) {
// show info if some files were not moved due to being embedded
showToast(message, "info");
} else {
showToast(`Successfully moved ${toMove.length} documents.`, "success");
}
await fetchKeys(true);
setSelectedItems({});
setLoading(false);
};
const handleSearch = debounce((e) => {
const searchValue = e.target.value;
setSearchTerm(searchValue);
}, 500);
const filteredFiles =filterFileSearchResults(files, searchTerm)
// console.log(114545,filteredFiles);
const handleContextMenu = (event) => {
event.preventDefault();
// setContextMenu({ visible: true, x: event.clientX, y: event.clientY });
};
const closeContextMenu = () => {
// setContextMenu({ visible: false, x: 0, y: 0 });
};
// 点击显示隐藏
const bindUrl = () =>{
setShow(!show)
console.log(show);
}
// 返回首页
const bindHome = () =>{
window.location = '/'
}
return (
<>
<div className="px-8 pb-8 w-[60%] mt-[30px] ml-[20px] pt-[10px] shadow-lg shadow-[0_0_20px_0_#F4F6FC] onContextMenu={handleContextMenu}">
<div className="flex flex-col gap-y-6">
<div className="flex items-center justify-between w-[100%] px-5 relative">
<h3 className="text-white text-base font-bold cursor-pointer text-[22px]" onClick={bindHome}>首页</h3>
<div className="relative">
<input
type="search"
placeholder="搜寻文件"
onChange={handleSearch}
className="border-none search-input bg-[#ECEFF6] text-white placeholder:text-theme-settings-input-placeholder focus:outline-primary-button active:outline-primary-button outline-none text-sm rounded-lg pl-9 pr-2.5 py-2 w-[600px] h-[32px] light:border-theme-modal-border light:border"
/>
<MagnifyingGlass
size={14}
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-white"
weight="bold"
/>
</div>
<button
className="border-none flex items-center gap-x-2 cursor-pointer px-[14px] py-[7px] -mr-[14px] rounded-lg hover:bg-theme-sidebar-subitem-hover z-20 relative"
onClick={openFolderModal}
>
<Plus
size={18}
weight="bold"
className="text-theme-text-primary light:text-[#0ba5ec]"
/>
<div className="text-theme-text-primary light:text-[#0ba5ec] text-xs font-bold leading-[18px]">
新文件夹
</div>
</button>
</div>
<div className="relative w-[100%] h-[500px] bg-[#ECEFF6] rounded-2xl overflow-hidden border ">
<div className="absolute top-0 left-0 right-0 z-10 rounded-t-2xl text-theme-text-primary text-xs grid grid-cols-12 py-2 px-8 border-b border-white/20 shadow-md ">
<p className="col-span-6">Name</p>
</div>
<div className="overflow-y-auto h-full pt-8">
{loading ? (
<div className="w-full h-full flex items-center justify-center flex-col gap-y-5">
<PreLoader />
<p className="text-white text-sm font-semibold animate-pulse text-center w-1/3">
{loadingMessage}
</p>
</div>
) : dataTo.length > 0 ? (
dataTo.map((item, index) => (
<div key={index} onClick={bindUrl}>
<div className="hover:bg-slate-400 pt-[10px] pb-[10px] pl-[30px] hover:text-[#fff]">{item.title}</div>
</div>
))
) : (
<div className="w-full h-full flex items-center justify-center">
<p className="text-white text-opacity-40 text-sm font-medium">
暂无文件
</p>
</div>
)}
</div>
{show == true && (
<div className="absolute bottom-[12px] left-0 right-0 flex justify-center pointer-events-none">
<div className="mx-auto bg-white/40 light:bg-white rounded-lg py-1 px-2 pointer-events-auto light:shadow-lg">
<div className="flex flex-row items-center gap-x-2">
<button
// onClick={moveToWorkspace}
onMouseEnter={() => setHighlightWorkspace(true)}
onMouseLeave={() => setHighlightWorkspace(false)}
className="border-none text-sm font-semibold bg-white light:bg-[#E0F2FE] h-[30px] px-2.5 rounded-lg hover:bg-neutral-800/80 hover:text-white light:text-[#026AA2] light:hover:bg-[#026AA2] light:hover:text-white"
>
设为私有
</button>
<button
// onClick={moveToWorkspace}
onMouseEnter={() => setHighlightWorkspace(true)}
onMouseLeave={() => setHighlightWorkspace(false)}
className="border-none text-sm font-semibold bg-white light:bg-[#E0F2FE] h-[30px] px-2.5 rounded-lg hover:bg-neutral-800/80 hover:text-white light:text-[#026AA2] light:hover:bg-[#026AA2] light:hover:text-white"
>
设为公有
</button>
<button
// onClick={moveToWorkspace}
onMouseEnter={() => setHighlightWorkspace(true)}
onMouseLeave={() => setHighlightWorkspace(false)}
className="border-none text-sm font-semibold bg-white light:bg-[#E0F2FE] h-[30px] px-2.5 rounded-lg hover:bg-neutral-800/80 hover:text-white light:text-[#026AA2] light:hover:bg-[#026AA2] light:hover:text-white"
>
添加标签
</button>
<div className="relative">
<button
// onClick={() =>
// setShowFolderSelection(!showFolderSelection)
// }
className="border-none text-sm font-semibold bg-white light:bg-[#E0F2FE] h-[32px] w-[32px] rounded-lg text-dark-text hover:bg-neutral-800/80 hover:text-white light:text-[#026AA2] light:hover:bg-[#026AA2] light:hover:text-white flex justify-center items-center group"
>
<MoveToFolderIcon className="text-dark-text light:text-[#026AA2] group-hover:text-white" />
</button>
{showFolderSelection && (
<FolderSelectionPopup
folders={files.items.filter(
(item) => item.type === "folder"
)}
onSelect={moveToFolder}
onClose={() => setShowFolderSelection(false)}
/>
)}
</div>
<button
// onClick={deleteFiles}
className="border-none text-sm font-semibold bg-white light:bg-[#E0F2FE] h-[32px] w-[32px] rounded-lg text-dark-text hover:bg-neutral-800/80 hover:text-white light:text-[#026AA2] light:hover:bg-[#026AA2] light:hover:text-white flex justify-center items-center"
>
<Trash size={18} weight="bold" />
</button>
</div>
</div>
</div>
)}
</div>
<UploadFile
workspace={workspace}
fetchKeys={fetchKeys}
setLoading={setLoading}
setLoadingMessage={setLoadingMessage}
/>
</div>
{isFolderModalOpen && (
<div className="bg-black/60 backdrop-blur-sm fixed top-0 left-0 outline-none w-screen h-screen flex items-center justify-center z-30">
<NewFolderModal
closeModal={closeFolderModal}
files={files}
setFiles={setFiles}
/>
</div>
)}
{/* <ContextMenu
contextMenu={contextMenu}
closeContextMenu={closeContextMenu}
files={files}
selectedItems={selectedItems}
setSelectedItems={setSelectedItems}
/> */}
</div>
<DirectoryTooltips />
</>
);
}
/**
* Tooltips for the directory components. Renders when the directory is shown
* or updated so that tooltips are attached as the items are changed.
*/
function DirectoryTooltips() {
return (
<Tooltip
id="directory-item"
place="bottom"
delayShow={800}
className="tooltip invert light:invert-0 z-99 max-w-[200px]"
render={({ content }) => {
const data = safeJsonParse(content, null);
if (!data) return null;
return (
<div className="text-xs">
<p className="text-white light:invert font-medium">{data.title}</p>
<div className="flex mt-1 gap-x-2">
<p className="">
Date: <b>{data.date}</b>
</p>
<p className="">
Type: <b>{data.extension}</b>
</p>
</div>
</div>
);
}}
/>
);
}
export default memo(Directory);