implement search for document picker

This commit is contained in:
shatfield4 2024-05-24 17:14:11 -07:00
parent c24b79c9d1
commit fad1129b33
2 changed files with 166 additions and 59 deletions

View File

@ -0,0 +1,90 @@
import React, { useState } from "react";
import { X } from "@phosphor-icons/react";
import Document from "@/models/document";
export default function NewFolderModal({ closeModal, files, setFiles }) {
const [error, setError] = useState(null);
const [folderName, setFolderName] = useState("");
const handleCreate = async (e) => {
e.preventDefault();
setError(null);
if (folderName.trim() !== "") {
const newFolder = {
name: folderName,
type: "folder",
items: [],
};
const { success } = await Document.createFolder(folderName);
if (success) {
setFiles({
...files,
items: [...files.items, newFolder],
});
closeModal();
} else {
setError("Failed to create folder");
}
}
};
return (
<div className="relative w-full max-w-2xl max-h-full">
<div className="relative bg-main-gradient rounded-lg shadow">
<div className="flex items-start justify-between p-4 border-b rounded-t border-gray-500/50">
<h3 className="text-xl font-semibold text-white">
Create New Folder
</h3>
<button
onClick={closeModal}
type="button"
className="transition-all duration-300 text-gray-400 bg-transparent hover:border-white/60 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border"
data-modal-hide="staticModal"
>
<X className="text-gray-300 text-lg" />
</button>
</div>
<form onSubmit={handleCreate}>
<div className="p-6 space-y-6 flex h-full w-full">
<div className="w-full flex flex-col gap-y-4">
<div>
<label
htmlFor="folderName"
className="block mb-2 text-sm font-medium text-white"
>
Folder Name
</label>
<input
name="folderName"
type="text"
className="bg-zinc-900 placeholder:text-white/20 border-gray-500 text-white text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
placeholder="Enter folder name"
required={true}
autoComplete="off"
value={folderName}
onChange={(e) => setFolderName(e.target.value)}
/>
</div>
{error && <p className="text-red-400 text-sm">Error: {error}</p>}
</div>
</div>
<div className="flex w-full justify-between items-center p-6 space-x-2 border-t rounded-b border-gray-500/50">
<button
onClick={closeModal}
type="button"
className="px-4 py-2 rounded-lg text-white hover:bg-stone-900 transition-all duration-300"
>
Cancel
</button>
<button
type="submit"
className="transition-all duration-300 border border-slate-200 px-4 py-2 rounded-lg text-white text-sm items-center flex gap-x-2 hover:bg-slate-200 hover:text-slate-800 focus:ring-gray-800"
>
Create Folder
</button>
</div>
</form>
</div>
</div>
);
}

View File

@ -3,11 +3,15 @@ import PreLoader from "@/components/Preloader";
import { memo, useEffect, useState } from "react";
import FolderRow from "./FolderRow";
import System from "@/models/system";
import { Plus, Trash } from "@phosphor-icons/react";
import { MagnifyingGlass, Plus, Trash } from "@phosphor-icons/react";
import Document from "@/models/document";
import showToast from "@/utils/toast";
import FolderSelectionPopup from "./FolderSelectionPopup";
import MoveToFolderIcon from "./MoveToFolderIcon";
import { useModal } from "@/hooks/useModal";
import ModalWrapper from "@/components/ModalWrapper";
import NewFolderModal from "./NewFolderModal";
import debounce from "lodash.debounce";
function Directory({
files,
@ -24,9 +28,14 @@ function Directory({
loadingMessage,
}) {
const [amountSelected, setAmountSelected] = useState(0);
const [newFolderName, setNewFolderName] = useState("");
const [showNewFolderInput, setShowNewFolderInput] = useState(false);
const [showFolderSelection, setShowFolderSelection] = useState(false);
const [searchTerm, setSearchTerm] = useState("");
const [isSearching, setIsSearching] = useState(false);
const {
isOpen: isFolderModalOpen,
openModal: openFolderModal,
closeModal: closeFolderModal,
} = useModal();
useEffect(() => {
setAmountSelected(Object.keys(selectedItems).length);
@ -121,32 +130,6 @@ function Directory({
return !!selectedItems[id];
};
const createNewFolder = () => {
setShowNewFolderInput(true);
};
const confirmNewFolder = async () => {
if (newFolderName.trim() !== "") {
const newFolder = {
name: newFolderName,
type: "folder",
items: [],
};
// If folder failed to create - silently fail.
const { success } = await Document.createFolder(newFolderName);
if (success) {
setFiles({
...files,
items: [...files.items, newFolder],
});
}
setNewFolderName("");
setShowNewFolderInput(false);
}
};
const moveToFolder = async (folder) => {
const toMove = [];
for (const itemId of Object.keys(selectedItems)) {
@ -183,40 +166,61 @@ function Directory({
setLoading(false);
};
const filterFiles = (item) => {
if (item.type === "folder") {
return (
item.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
item.items.some((file) =>
file.name.toLowerCase().includes(searchTerm.toLowerCase())
)
);
} else {
return item.name.toLowerCase().includes(searchTerm.toLowerCase());
}
};
const debouncedSearch = debounce((value) => {
setSearchTerm(value);
setIsSearching(false);
}, 500);
const handleSearch = (e) => {
const searchValue = e.target.value;
setSearchTerm(searchValue);
setIsSearching(true);
debouncedSearch(searchValue);
};
const filteredFiles =
files && files.items ? files.items.filter((item) => filterFiles(item)) : [];
return (
<div className="px-8 pb-8">
<div className="flex flex-col gap-y-6">
<div className="flex items-center justify-between w-[560px] px-5 relative">
<h3 className="text-white text-base font-bold">My Documents</h3>
{showNewFolderInput ? (
<div className="flex items-center gap-x-2 z-50">
<div className="relative">
<input
type="text"
placeholder="Folder name"
value={newFolderName}
onChange={(e) => setNewFolderName(e.target.value)}
className="bg-zinc-900 text-white placeholder-white/20 text-sm rounded-md p-2.5 w-[150px] h-[32px]"
placeholder="Search"
onChange={handleSearch}
className="bg-zinc-900 text-white placeholder-white/80 text-sm rounded-lg pl-9 pr-2.5 py-2 w-[250px] h-[32px]"
/>
<MagnifyingGlass
size={14}
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-white"
weight="bold"
/>
<div className="flex gap-x-2">
<button
onClick={confirmNewFolder}
className="text-sky-400 rounded-md text-sm font-bold hover:text-sky-500"
>
Create
</button>
</div>
</div>
) : (
<button
className="flex items-center gap-x-2 cursor-pointer px-[14px] py-[7px] -mr-[14px] rounded-lg hover:bg-[#222628]/60"
onClick={createNewFolder}
onClick={openFolderModal}
>
<Plus size={18} weight="bold" color="#D3D4D4" />
<div className="text-[#D3D4D4] text-xs font-bold leading-[18px]">
New Folder
</div>
</button>
)}
</div>
<div className="relative w-[560px] h-[310px] bg-zinc-900 rounded-2xl overflow-hidden">
@ -234,8 +238,12 @@ function Directory({
{loadingMessage}
</p>
</div>
) : files.items ? (
files.items.map(
) : isSearching && searchTerm !== "" ? (
<div className="w-full h-full flex items-center justify-center">
<PreLoader />
</div>
) : filteredFiles.length > 0 ? (
filteredFiles.map(
(item, index) =>
item.type === "folder" && (
<FolderRow
@ -302,6 +310,7 @@ function Directory({
</div>
)}
</div>
<UploadFile
workspace={workspace}
fetchKeys={fetchKeys}
@ -309,6 +318,14 @@ function Directory({
setLoadingMessage={setLoadingMessage}
/>
</div>
<ModalWrapper isOpen={isFolderModalOpen}>
<NewFolderModal
closeModal={closeFolderModal}
files={files}
setFiles={setFiles}
/>
</ModalWrapper>
</div>
);
}