|
|
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);
|