added multiselect logic, implemented trash and multi trash
This commit is contained in:
@@ -5,24 +5,31 @@ import {
|
||||
deleteFileAPI,
|
||||
renameFileAPI,
|
||||
downloadFileAPI,
|
||||
trashFileAPI,
|
||||
} from "../../api/filesAPI";
|
||||
import { useFilesClient, useQuickFilesClient } from "../../hooks/files";
|
||||
import { useFoldersClient } from "../../hooks/folders";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { setMoverID } from "../../actions/mover";
|
||||
import { setShareSelected } from "../../actions/selectedItem";
|
||||
import { deleteFolder, renameFolder } from "../../api/foldersAPI";
|
||||
import {
|
||||
deleteFolder,
|
||||
renameFolder,
|
||||
trashFolderAPI,
|
||||
} from "../../api/foldersAPI";
|
||||
import { useClickOutOfBounds } from "../../hooks/utils";
|
||||
import { useAppDispatch } from "../../hooks/store";
|
||||
import { setMultiSelectMode } from "../../reducers/selected";
|
||||
|
||||
const ContextMenu = (props) => {
|
||||
const { invalidateFilesCache } = useFilesClient();
|
||||
const { invalidateFoldersCache } = useFoldersClient();
|
||||
const { invalidateQuickFilesCache } = useQuickFilesClient();
|
||||
const { wrapperRef } = useClickOutOfBounds(props.closeContext);
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
const liClassname =
|
||||
"flex w-full px-[20px] py-[12px] items-center font-normal text-[#637381] justify-start no-underline transition-all duration-400 ease-in-out text- hover:bg-[#f6f5fd] hover:text-[#3c85ee] hover:font-medium";
|
||||
const spanClassname = "inline-flex mr-[18px]";
|
||||
const spanClassname = "flex items-center justify-center mr-[18px]";
|
||||
|
||||
const renameItem = async () => {
|
||||
props.closeContext();
|
||||
@@ -67,32 +74,32 @@ const ContextMenu = (props) => {
|
||||
props.closeContext();
|
||||
if (!props.folderMode) {
|
||||
const result = await Swal.fire({
|
||||
title: "Confirm Deletion",
|
||||
text: "You cannot undo this action",
|
||||
title: "Move to trash?",
|
||||
text: "Items in the trash will eventually be deleted.",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes, delete",
|
||||
confirmButtonText: "Yes",
|
||||
});
|
||||
|
||||
if (result.value) {
|
||||
await deleteFileAPI(props.file._id);
|
||||
await trashFileAPI(props.file._id);
|
||||
invalidateFilesCache();
|
||||
invalidateQuickFilesCache();
|
||||
}
|
||||
} else {
|
||||
const result = await Swal.fire({
|
||||
title: "Confirm Deletion",
|
||||
text: "You cannot undo this action",
|
||||
title: "Move to trash?",
|
||||
text: "Items in the trash will eventually be deleted.",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes, delete",
|
||||
confirmButtonText: "Yes",
|
||||
});
|
||||
if (result.value) {
|
||||
await deleteFolder(props.folder._id, props.folder.parentList);
|
||||
await trashFolderAPI(props.folder._id);
|
||||
invalidateFoldersCache();
|
||||
}
|
||||
}
|
||||
@@ -117,6 +124,29 @@ const ContextMenu = (props) => {
|
||||
downloadFileAPI(props.file._id);
|
||||
};
|
||||
|
||||
const selectItemMultiSelect = () => {
|
||||
props.closeContext();
|
||||
if (props.folderMode) {
|
||||
dispatch(
|
||||
setMultiSelectMode({
|
||||
type: "folder",
|
||||
id: props.folder._id,
|
||||
file: null,
|
||||
folder: props.folder,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
dispatch(
|
||||
setMultiSelectMode({
|
||||
type: props.quickItemMode ? "quick-item" : "file",
|
||||
id: props.file._id,
|
||||
file: props.file,
|
||||
folder: null,
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={props.stopPropagation}
|
||||
@@ -136,6 +166,18 @@ const ContextMenu = (props) => {
|
||||
}
|
||||
>
|
||||
<ul className="p-0 list-none m-0 ">
|
||||
<li onClick={selectItemMultiSelect} className={liClassname}>
|
||||
<a className="flex">
|
||||
<span className={spanClassname}>
|
||||
<img
|
||||
src="/assets/checkbox-multiple-outline.svg"
|
||||
alt="multiselect"
|
||||
className="w-[19px] h-[20px]"
|
||||
/>
|
||||
</span>
|
||||
Multi select
|
||||
</a>
|
||||
</li>
|
||||
<li onClick={renameItem} className={liClassname}>
|
||||
<a className="flex">
|
||||
<span className={spanClassname}>
|
||||
@@ -180,7 +222,7 @@ const ContextMenu = (props) => {
|
||||
<span className={spanClassname}>
|
||||
<img src="/assets/filesetting5.svg" alt="setting" />
|
||||
</span>
|
||||
Delete
|
||||
Trash
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -3,9 +3,15 @@ import Folders from "../Folders";
|
||||
import { useFiles } from "../../hooks/files";
|
||||
import { useInfiniteScroll } from "../../hooks/infiniteScroll";
|
||||
import Files from "../Files";
|
||||
import { memo, useEffect, useState } from "react";
|
||||
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
||||
import SpinnerPage from "../SpinnerPage";
|
||||
import SearchBar from "../SearchBar";
|
||||
import { useAppDispatch } from "../../hooks/store";
|
||||
import { startAddFile } from "../../actions/files";
|
||||
import { useParams } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
import { useDragAndDrop } from "../../hooks/utils";
|
||||
import MultiSelectBar from "../MultiSelectBar";
|
||||
|
||||
const DataForm = memo(() => {
|
||||
const {
|
||||
@@ -13,8 +19,10 @@ const DataForm = memo(() => {
|
||||
isFetchingNextPage,
|
||||
data: fileList,
|
||||
} = useFiles();
|
||||
const dispatch = useAppDispatch();
|
||||
const { sentinelRef, reachedIntersect } = useInfiniteScroll();
|
||||
const [initialLoad, setInitialLoad] = useState(true);
|
||||
const params = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (initialLoad) {
|
||||
@@ -28,8 +36,34 @@ const DataForm = memo(() => {
|
||||
}
|
||||
}, [reachedIntersect, initialLoad, isFetchingNextPage]);
|
||||
|
||||
const addFile = useCallback(
|
||||
(file) => {
|
||||
dispatch(startAddFile(file, params.id));
|
||||
},
|
||||
[params.id]
|
||||
);
|
||||
|
||||
const {
|
||||
isDraggingFile,
|
||||
onDragDropEvent,
|
||||
onDragEvent,
|
||||
onDragEnterEvent,
|
||||
stopDrag,
|
||||
} = useDragAndDrop(addFile);
|
||||
|
||||
return (
|
||||
<div className="w-full p-[65px_40px] overflow-y-scroll">
|
||||
<div
|
||||
className={classNames("w-full p-[17px_40px] overflow-y-scroll", {
|
||||
"opacity-50": isDraggingFile,
|
||||
})}
|
||||
onDrop={onDragDropEvent}
|
||||
onDragOver={onDragEvent}
|
||||
onDragLeave={onDragEvent}
|
||||
onDragEnter={onDragEnterEvent}
|
||||
onMouseLeave={stopDrag}
|
||||
>
|
||||
<MultiSelectBar />
|
||||
|
||||
<QuickAccess />
|
||||
|
||||
<Folders />
|
||||
|
||||
@@ -12,7 +12,7 @@ import { startSetSelectedItem } from "../../actions/selectedItem";
|
||||
import { setPopupFile } from "../../actions/popupFile";
|
||||
import bytes from "bytes";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { setMainSelect } from "../../reducers/selected";
|
||||
import { setMainSelect, setMultiSelectMode } from "../../reducers/selected";
|
||||
|
||||
const FileItem = React.memo((props) => {
|
||||
const { file } = props;
|
||||
@@ -20,6 +20,14 @@ const FileItem = React.memo((props) => {
|
||||
if (state.selected.mainSection.type !== "file") return false;
|
||||
return state.selected.mainSection.id === file._id;
|
||||
});
|
||||
const elementMultiSelected = useAppSelector((state) => {
|
||||
if (!state.selected.multiSelectMode) return false;
|
||||
const selected = state.selected.multiSelectMap[file._id];
|
||||
return selected && selected.type === "file";
|
||||
});
|
||||
const multiSelectMode = useAppSelector(
|
||||
(state) => state.selected.multiSelectMode
|
||||
);
|
||||
const listView = useSelector((state) => state.filter.listView);
|
||||
const { image, hasThumbnail, imageOnError } = useThumbnail(
|
||||
file.metadata.hasThumbnail,
|
||||
@@ -58,6 +66,18 @@ const FileItem = React.memo((props) => {
|
||||
|
||||
// TODO: See if we can memoize this
|
||||
const fileClick = () => {
|
||||
if (multiSelectMode) {
|
||||
dispatch(
|
||||
setMultiSelectMode({
|
||||
type: "file",
|
||||
id: file._id,
|
||||
file: file,
|
||||
folder: null,
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const currentDate = Date.now();
|
||||
|
||||
if (!elementSelected) {
|
||||
@@ -82,7 +102,7 @@ const FileItem = React.memo((props) => {
|
||||
<tr
|
||||
className={classNames(
|
||||
"text-[14px] font-normal border-y",
|
||||
!elementSelected
|
||||
!elementSelected && !elementMultiSelected
|
||||
? "text-[#212b36] hover:bg-[#f6f5fd]"
|
||||
: "bg-[#3c85ee] animate text-white"
|
||||
)}
|
||||
@@ -137,7 +157,9 @@ const FileItem = React.memo((props) => {
|
||||
<svg
|
||||
className={classNames(
|
||||
"w-4 h-4",
|
||||
elementSelected ? "text-white" : "text-[#919eab]"
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-[#919eab]"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
@@ -162,8 +184,10 @@ const FileItem = React.memo((props) => {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"border rounded-md o transition-all duration-400 ease-in-out cursor-pointer flex items-center justify-center flex-col h-[125px] sm:h-[150px] animiate hover:border-[#3c85ee] overflow-hidden",
|
||||
elementSelected ? "border-[#3c85ee]" : "border-[#ebe9f9]"
|
||||
"border rounded-md o transition-all duration-400 ease-in-out cursor-pointer flex items-center justify-center flex-col h-[125px] sm:h-[150px] animiate hover:border-[#3c85ee] overflow-hidden bg-white",
|
||||
elementSelected || elementMultiSelected
|
||||
? "border-[#3c85ee]"
|
||||
: "border-[#ebe9f9]"
|
||||
)}
|
||||
onClick={fileClick}
|
||||
onContextMenu={onContextMenu}
|
||||
@@ -175,7 +199,7 @@ const FileItem = React.memo((props) => {
|
||||
<div onClick={clickStopPropagation}>
|
||||
<ContextMenu
|
||||
gridMode={true}
|
||||
quickItemMode={true}
|
||||
quickItemMode={false}
|
||||
contextSelected={contextMenuState}
|
||||
closeContext={closeContextMenu}
|
||||
file={file}
|
||||
@@ -221,7 +245,7 @@ const FileItem = React.memo((props) => {
|
||||
<div
|
||||
className={classNames(
|
||||
"p-3 overflow-hidden text-ellipsis block w-full animate",
|
||||
elementSelected
|
||||
elementSelected || elementMultiSelected
|
||||
? "bg-[#3c85ee] text-white"
|
||||
: "bg-white text-[#637381]"
|
||||
)}
|
||||
@@ -229,7 +253,9 @@ const FileItem = React.memo((props) => {
|
||||
<p
|
||||
className={classNames(
|
||||
"m-0 text-[14px] leading-[16px] font-normal max-w-full overflow-hidden text-ellipsis whitespace-nowrap animate",
|
||||
elementSelected ? "text-white" : "text-[#212b36]"
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-[#212b36]"
|
||||
)}
|
||||
>
|
||||
{formattedFilename}
|
||||
@@ -237,7 +263,9 @@ const FileItem = React.memo((props) => {
|
||||
<span
|
||||
className={classNames(
|
||||
"m-0 text-[#637381] font-normal max-w-full whitespace-nowrap text-xs animate hidden sm:block mt-1",
|
||||
elementSelected ? "text-white" : "text-[#637381]"
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-[#637381]"
|
||||
)}
|
||||
>
|
||||
Created {formattedCreatedDate}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { startSetSelectedItem } from "../../actions/selectedItem";
|
||||
import mobilecheck from "../../utils/mobileCheck";
|
||||
import moment from "moment";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { setMainSelect } from "../../reducers/selected";
|
||||
import { setMainSelect, setMultiSelectMode } from "../../reducers/selected";
|
||||
|
||||
const FolderItem = React.memo((props) => {
|
||||
const { folder } = props;
|
||||
@@ -16,6 +16,13 @@ const FolderItem = React.memo((props) => {
|
||||
if (state.selected.mainSection.type !== "folder") return false;
|
||||
return state.selected.mainSection.id === folder._id;
|
||||
});
|
||||
const elementMultiSelected = useAppSelector((state) => {
|
||||
if (!state.selected.multiSelectMode) return false;
|
||||
return state.selected.multiSelectMap[folder._id];
|
||||
});
|
||||
const multiSelectMode = useAppSelector(
|
||||
(state) => state.selected.multiSelectMode
|
||||
);
|
||||
const lastSelected = useRef(0);
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -30,6 +37,17 @@ const FolderItem = React.memo((props) => {
|
||||
} = useContextMenu();
|
||||
|
||||
const folderClick = useCallback(() => {
|
||||
if (multiSelectMode) {
|
||||
dispatch(
|
||||
setMultiSelectMode({
|
||||
type: "folder",
|
||||
id: folder._id,
|
||||
file: null,
|
||||
folder: folder,
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
const currentDate = Date.now();
|
||||
|
||||
if (!elementSelected) {
|
||||
@@ -58,14 +76,15 @@ const FolderItem = React.memo((props) => {
|
||||
navigate,
|
||||
folder._id,
|
||||
elementSelected,
|
||||
multiSelectMode,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"p-[12px] border border-[#ebe9f9] rounded-[4px] overflow-hidden cursor-pointer animate ",
|
||||
"p-[12px] border border-[#ebe9f9] rounded-[4px] overflow-hidden cursor-pointer animate hover:border-[#3c85ee]",
|
||||
{
|
||||
"bg-[#3c85ee]": elementSelected,
|
||||
"bg-[#3c85ee]": elementSelected || elementMultiSelected,
|
||||
}
|
||||
)}
|
||||
onClick={folderClick}
|
||||
@@ -91,7 +110,9 @@ const FolderItem = React.memo((props) => {
|
||||
<svg
|
||||
className={classNames(
|
||||
"w-[40px] h-[40px]",
|
||||
elementSelected ? "text-white" : "text-[#3c85ee]"
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-[#3c85ee]"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
@@ -111,7 +132,7 @@ const FolderItem = React.memo((props) => {
|
||||
<div
|
||||
className={classNames(
|
||||
"overflow-hidden text-ellipsis block w-full animate mt-2",
|
||||
elementSelected
|
||||
elementSelected || elementMultiSelected
|
||||
? "bg-[#3c85ee] text-white"
|
||||
: "bg-white text-[#637381]"
|
||||
)}
|
||||
@@ -119,7 +140,9 @@ const FolderItem = React.memo((props) => {
|
||||
<p
|
||||
className={classNames(
|
||||
"m-0 text-[14px] leading-[16px] font-normal max-w-full overflow-hidden text-ellipsis whitespace-nowrap animate",
|
||||
elementSelected ? "text-white" : "text-black"
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-black"
|
||||
)}
|
||||
>
|
||||
{folder.name}
|
||||
@@ -127,7 +150,9 @@ const FolderItem = React.memo((props) => {
|
||||
<span
|
||||
className={classNames(
|
||||
"m-0 font-normal max-w-full whitespace-nowrap text-xs animate hidden sm:block mt-1",
|
||||
elementSelected ? "text-white" : "text-[#637381]"
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-[#637381]"
|
||||
)}
|
||||
>
|
||||
Created {moment(folder.createdAt).format("MM/DD/YY hh:mma")}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
import { useMemo } from "react";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { resetMultiSelect } from "../../reducers/selected";
|
||||
import Swal from "sweetalert2";
|
||||
import { trashMultiAPI } from "../../api/filesAPI";
|
||||
import { useFilesClient, useQuickFilesClient } from "../../hooks/files";
|
||||
import { useFoldersClient } from "../../hooks/folders";
|
||||
|
||||
const MultiSelectBar = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const multiSelectMode = useAppSelector(
|
||||
(state) => state.selected.multiSelectMode
|
||||
);
|
||||
const multiSelectMap = useAppSelector(
|
||||
(state) => state.selected.multiSelectMap
|
||||
);
|
||||
const multiSelectCount = useAppSelector(
|
||||
(state) => state.selected.multiSelectCount
|
||||
);
|
||||
const { invalidateFilesCache } = useFilesClient();
|
||||
const { invalidateFoldersCache } = useFoldersClient();
|
||||
const { invalidateQuickFilesCache } = useQuickFilesClient();
|
||||
|
||||
const closeMultiSelect = () => {
|
||||
dispatch(resetMultiSelect());
|
||||
};
|
||||
|
||||
const deleteItems = async () => {
|
||||
const result = await Swal.fire({
|
||||
title: "Move to trash?",
|
||||
text: "Items in the trash will eventually be deleted.",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes",
|
||||
});
|
||||
|
||||
if (result.value) {
|
||||
const itemsToTrash = Object.values(multiSelectMap);
|
||||
await trashMultiAPI(itemsToTrash);
|
||||
invalidateFilesCache();
|
||||
invalidateFoldersCache();
|
||||
invalidateQuickFilesCache();
|
||||
closeMultiSelect();
|
||||
}
|
||||
};
|
||||
|
||||
if (!multiSelectMode) return <div></div>;
|
||||
|
||||
return (
|
||||
<div className="border border-[#ebe9f9] bg-[#ebe9f9] rounded-full p-2 px-5 text-black text-sm mb-4">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex flex-row items-center">
|
||||
<img
|
||||
className="w-[22px] h-[22px] cursor-pointer"
|
||||
src="/images/close_icon.png"
|
||||
onClick={closeMultiSelect}
|
||||
/>
|
||||
<p className="ml-4">{multiSelectCount} selected</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center">
|
||||
<svg
|
||||
width="17"
|
||||
height="18"
|
||||
viewBox="0 0 17 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="ml-4 cursor-pointer"
|
||||
onClick={deleteItems}
|
||||
>
|
||||
<g id="trash">
|
||||
<path
|
||||
id="Shape"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M16.0694 2.57072H11.5707V1.92803C11.5707 0.863209 10.7075 0 9.64265 0H7.07192C6.0071 0 5.14389 0.863209 5.14389 1.92803V2.57072H0.645132C0.290178 2.57072 0.00244141 2.85846 0.00244141 3.21341C0.00244141 3.56837 0.290215 3.85607 0.645132 3.85607H1.34371L2.57317 17.4108C2.60348 17.7427 2.88255 17.9963 3.21586 17.995H13.4987C13.832 17.9964 14.1111 17.7427 14.1414 17.4108L15.3708 3.85607H16.0694C16.4244 3.85607 16.7121 3.56833 16.7121 3.21338C16.7121 2.85842 16.4244 2.57072 16.0694 2.57072ZM6.42923 1.92803C6.42923 1.57308 6.71697 1.28534 7.07192 1.28534H9.64265C9.9976 1.28534 10.2853 1.57308 10.2853 1.92803V2.57072H6.42927V1.92803H6.42923ZM3.80263 16.7096H12.9119L14.0803 3.85607H5.78658H2.63745L3.80263 16.7096Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
id="Path"
|
||||
d="M6.42938 14.7385C6.4293 14.7376 6.42926 14.7367 6.42919 14.7358L5.7865 5.73834C5.76131 5.38339 5.45312 5.1161 5.09821 5.14129C4.74325 5.16649 4.47596 5.47467 4.50116 5.82959L5.14385 14.8271C5.16783 15.1641 5.44868 15.425 5.78654 15.4241H5.83282C6.1869 15.3995 6.45401 15.0925 6.42938 14.7385Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
id="Path_2"
|
||||
d="M8.35729 5.1416C8.00234 5.1416 7.7146 5.42934 7.7146 5.78429V14.7818C7.7146 15.1367 8.00234 15.4245 8.35729 15.4245C8.71224 15.4245 8.99998 15.1367 8.99998 14.7818V5.78429C8.99998 5.42934 8.71224 5.1416 8.35729 5.1416Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
id="Path_3"
|
||||
d="M11.6164 5.14129C11.2615 5.1161 10.9533 5.38339 10.9281 5.73834L10.2854 14.7358C10.2594 15.0898 10.5253 15.3979 10.8793 15.4239C10.8804 15.424 10.8814 15.424 10.8825 15.4241H10.9281C11.266 15.425 11.5468 15.1641 11.5708 14.8271L12.2135 5.82959C12.2387 5.47467 11.9714 5.16652 11.6164 5.14129Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg
|
||||
width="19"
|
||||
height="16"
|
||||
viewBox="0 0 19 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="ml-4 cursor-pointer"
|
||||
>
|
||||
<path
|
||||
id="Combined Shape"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M7.63107 0C7.83994 0 8.03661 0.0983374 8.16193 0.265429L9.95357 2.65429H17.9164C18.2829 2.65429 18.58 2.95138 18.58 3.31786V15.2621C18.58 15.6286 18.2829 15.9257 17.9164 15.9257H0.663571C0.297091 15.9257 0 15.6286 0 15.2621V0.663571C0 0.297091 0.297091 0 0.663571 0H7.63107ZM7.212 1.5H1.5V14.425H17.08V4.154L9.20357 4.15429L7.212 1.5ZM9.96369 9.51348C10.0439 9.43969 10.0892 9.33783 10.0892 9.23078C10.0892 9.12373 10.0439 9.02188 9.96369 8.9486L7.2712 6.4802C7.15381 6.37263 6.98149 6.34301 6.8334 6.40433C6.68532 6.46565 6.58893 6.60648 6.58893 6.76238V7.93162H4.30032C3.92929 7.93162 3.62719 8.22315 3.62719 8.5812V9.88036C3.62719 10.2384 3.92929 10.5299 4.30032 10.5299H6.58893V11.6992C6.58893 11.8551 6.68478 11.9964 6.8334 12.0577C6.98203 12.1191 7.15435 12.0889 7.2712 11.9819L9.96369 9.51348Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MultiSelectBar;
|
||||
@@ -12,7 +12,7 @@ import { startSetSelectedItem } from "../../actions/selectedItem";
|
||||
import { setPopupFile } from "../../actions/popupFile";
|
||||
import { FileInterface } from "../../types/file";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { setMainSelect } from "../../reducers/selected";
|
||||
import { setMainSelect, setMultiSelectMode } from "../../reducers/selected";
|
||||
|
||||
interface QuickAccessItemProps {
|
||||
file: FileInterface;
|
||||
@@ -24,10 +24,18 @@ const QuickAccessItem = memo((props: QuickAccessItemProps) => {
|
||||
if (state.selected.mainSection.type !== "quick-item") return false;
|
||||
return state.selected.mainSection.id === file._id;
|
||||
});
|
||||
console.log("ele selected 2", elementSelected);
|
||||
const elementMultiSelected = useAppSelector((state) => {
|
||||
if (!state.selected.multiSelectMode) return false;
|
||||
const selected = state.selected.multiSelectMap[file._id];
|
||||
return selected && selected.type === "quick-item";
|
||||
});
|
||||
const multiSelectMode = useAppSelector(
|
||||
(state) => state.selected.multiSelectMode
|
||||
);
|
||||
const { image, hasThumbnail, imageOnError } = useThumbnail(
|
||||
file.metadata.hasThumbnail,
|
||||
file.metadata.thumbnailID
|
||||
file.metadata.thumbnailID,
|
||||
true
|
||||
);
|
||||
const dispatch = useAppDispatch();
|
||||
const lastSelected = useRef(0);
|
||||
@@ -54,6 +62,17 @@ const QuickAccessItem = memo((props: QuickAccessItemProps) => {
|
||||
|
||||
// TODO: See if we can memoize this
|
||||
const quickItemClick = () => {
|
||||
if (multiSelectMode) {
|
||||
dispatch(
|
||||
setMultiSelectMode({
|
||||
type: "quick-item",
|
||||
id: file._id,
|
||||
file: file,
|
||||
folder: null,
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
const currentDate = Date.now();
|
||||
|
||||
if (!elementSelected) {
|
||||
@@ -77,8 +96,10 @@ const QuickAccessItem = memo((props: QuickAccessItemProps) => {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"border rounded-md o transition-all duration-400 ease-in-out cursor-pointer flex items-center justify-center flex-col h-[125px] sm:h-[150px] animiate hover:border-[#3c85ee] overflow-hidden",
|
||||
elementSelected ? "border-[#3c85ee]" : "border-[#ebe9f9]"
|
||||
"border rounded-md o transition-all duration-400 ease-in-out cursor-pointer flex items-center justify-center flex-col h-[125px] sm:h-[150px] animiate hover:border-[#3c85ee] overflow-hidden bg-white",
|
||||
elementSelected || elementMultiSelected
|
||||
? "border-[#3c85ee]"
|
||||
: "border-[#ebe9f9]"
|
||||
)}
|
||||
onClick={quickItemClick}
|
||||
onContextMenu={onContextMenu}
|
||||
@@ -136,7 +157,7 @@ const QuickAccessItem = memo((props: QuickAccessItemProps) => {
|
||||
<div
|
||||
className={classNames(
|
||||
"p-3 overflow-hidden text-ellipsis block w-full animate",
|
||||
elementSelected
|
||||
elementSelected || elementMultiSelected
|
||||
? "bg-[#3c85ee] text-white"
|
||||
: "bg-white text-[#637381]"
|
||||
)}
|
||||
@@ -144,7 +165,9 @@ const QuickAccessItem = memo((props: QuickAccessItemProps) => {
|
||||
<p
|
||||
className={classNames(
|
||||
"m-0 text-[14px] leading-[16px] font-normal max-w-full overflow-hidden text-ellipsis whitespace-nowrap animate",
|
||||
elementSelected ? "text-white" : "text-[#212b36]"
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-[#212b36]"
|
||||
)}
|
||||
>
|
||||
{capitalize(file.filename)}
|
||||
@@ -152,7 +175,9 @@ const QuickAccessItem = memo((props: QuickAccessItemProps) => {
|
||||
<span
|
||||
className={classNames(
|
||||
"text-[#637381] font-normal max-w-full whitespace-nowrap text-xs animate hidden sm:block mt-1",
|
||||
elementSelected ? "text-white" : "text-[#637381]"
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-[#637381]"
|
||||
)}
|
||||
>
|
||||
Created {moment(file.uploadDate).format("MM/DD/YY hh:mma")}
|
||||
|
||||
@@ -26,7 +26,7 @@ const SearchBarItem = (props: SearchBarItemProps) => {
|
||||
if (type === "folder" && folder) {
|
||||
return (
|
||||
<div
|
||||
className="flex flex-row items-center py-2 px-4 overflow-hidden text-ellipsis hover:bg-[#f6f5fd] cursor-pointer"
|
||||
className="flex flex-row items-center py-2 px-4 overflow-hidden text-ellipsis hover:bg-[#f6f5fd] cursor-pointer border-y mx-4"
|
||||
key={folder._id}
|
||||
onClick={() => folderClick(folder)}
|
||||
>
|
||||
@@ -48,7 +48,7 @@ const SearchBarItem = (props: SearchBarItemProps) => {
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-sm ml-4 text-ellipsis overflow-hidden whitespace-nowrap">
|
||||
<span className="text-sm ml-4 text-ellipsis overflow-hidden whitespace-nowrap max-w-[50%]">
|
||||
{folder.name}
|
||||
</span>
|
||||
</div>
|
||||
@@ -56,7 +56,7 @@ const SearchBarItem = (props: SearchBarItemProps) => {
|
||||
} else if (type === "file" && file) {
|
||||
return (
|
||||
<div
|
||||
className="flex flex-row items-center py-2 px-4 overflow-hidden text-ellipsis hover:bg-[#f6f5fd] cursor-pointer"
|
||||
className="flex flex-row items-center py-2 px-4 overflow-hidden text-ellipsis hover:bg-[#f6f5fd] cursor-pointer border-y mx-4"
|
||||
key={file._id}
|
||||
onClick={() => fileClick(file)}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user