lots of UI improvements
This commit is contained in:
@@ -8,6 +8,7 @@ export const moveFolderListValidationRules = [
|
||||
query("parent").optional().isString().withMessage("Parent must be a string"),
|
||||
query("search").optional().isString().withMessage("Search must be a string"),
|
||||
query("folderIDs")
|
||||
.optional()
|
||||
.isArray()
|
||||
.isLength({ min: 1 })
|
||||
.withMessage("FolderIDs must be an array of strings"),
|
||||
|
||||
@@ -98,7 +98,10 @@ const AddNewDropdown: React.FC<AddNewDropdownProps> = (props) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={wrapperRef} className="absolute bottom-0 top-full w-full">
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className="absolute bottom-0 top-full w-full text-gray-500"
|
||||
>
|
||||
<input
|
||||
className="hidden"
|
||||
ref={uploadRef}
|
||||
@@ -121,7 +124,7 @@ const AddNewDropdown: React.FC<AddNewDropdownProps> = (props) => {
|
||||
className="flex items-center justify-start px-5 py-3 no-underline overflow-hidden text-sm bg-white hover:bg-white-hover"
|
||||
onClick={triggerFileUpload}
|
||||
>
|
||||
<UploadFileIcon className="w-5 h-5 mr-2.5 text-primary" />
|
||||
<UploadFileIcon className="w-4 h-4 mr-2.5 text-primary" />
|
||||
<p className="text-sm">Upload Files</p>
|
||||
</a>
|
||||
</div>
|
||||
@@ -131,7 +134,7 @@ const AddNewDropdown: React.FC<AddNewDropdownProps> = (props) => {
|
||||
className="flex items-center justify-start px-5 py-3 no-underline overflow-hidden text-sm bg-white hover:bg-white-hover"
|
||||
onClick={createFolder}
|
||||
>
|
||||
<CreateFolderIcon className="w-5 h-5 mr-2.5 text-primary" />
|
||||
<CreateFolderIcon className="w-4 h-4 mr-2.5 text-primary" />
|
||||
<p className="text-sm">Create Folder</p>
|
||||
</a>
|
||||
</li>
|
||||
@@ -141,7 +144,7 @@ const AddNewDropdown: React.FC<AddNewDropdownProps> = (props) => {
|
||||
className="flex items-center justify-start px-5 py-3 no-underline overflow-hidden text-sm bg-white hover:bg-white-hover"
|
||||
onClick={triggerFolderUpload}
|
||||
>
|
||||
<FolderUploadIcon className="w-5 h-5 mr-2.5 text-primary" />
|
||||
<FolderUploadIcon className="w-4 h-4 mr-2.5 text-primary" />
|
||||
<p className="text-sm">Upload Folder</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1,27 +1,5 @@
|
||||
import React, { memo, useEffect, useState } from "react";
|
||||
import {
|
||||
deleteFileAPI,
|
||||
renameFileAPI,
|
||||
downloadFileAPI,
|
||||
trashFileAPI,
|
||||
restoreFileAPI,
|
||||
} from "../../api/filesAPI";
|
||||
import { useFiles, useQuickFiles } from "../../hooks/files";
|
||||
import {
|
||||
deleteFolderAPI,
|
||||
downloadZIPAPI,
|
||||
renameFolder,
|
||||
restoreFolderAPI,
|
||||
trashFolderAPI,
|
||||
} from "../../api/foldersAPI";
|
||||
import { useClickOutOfBounds, useUtils } from "../../hooks/utils";
|
||||
import { useAppDispatch } from "../../hooks/store";
|
||||
import {
|
||||
resetSelected,
|
||||
setMoveModal,
|
||||
setMultiSelectMode,
|
||||
setShareModal,
|
||||
} from "../../reducers/selected";
|
||||
import TrashIcon from "../../icons/TrashIcon";
|
||||
import MultiSelectIcon from "../../icons/MultiSelectIcon";
|
||||
import RenameIcon from "../../icons/RenameIcon";
|
||||
@@ -29,18 +7,10 @@ import ShareIcon from "../../icons/ShareIcon";
|
||||
import DownloadIcon from "../../icons/DownloadIcon";
|
||||
import MoveIcon from "../../icons/MoveIcon";
|
||||
import RestoreIcon from "../../icons/RestoreIcon";
|
||||
import {
|
||||
deleteFilePopup,
|
||||
renameFilePopup,
|
||||
restoreItemPopup,
|
||||
trashItemsPopup,
|
||||
} from "../../popups/file";
|
||||
import { FileInterface } from "../../types/file";
|
||||
import { FolderInterface } from "../../types/folders";
|
||||
import { toast } from "react-toastify";
|
||||
import { deleteFolderPopup, renameFolderPopup } from "../../popups/folder";
|
||||
import { useFolder, useFolders } from "../../hooks/folders";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useActions } from "../../hooks/actions";
|
||||
import { FolderInterface } from "../../types/folders";
|
||||
|
||||
export interface ContextMenuProps {
|
||||
closeContext: () => void;
|
||||
@@ -63,10 +33,6 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
Y: 0,
|
||||
set: false,
|
||||
});
|
||||
const { refetch: refetchFiles } = useFiles(false);
|
||||
const { refetch: refetchFolders } = useFolders(false);
|
||||
const { refetch: refetchFolder } = useFolder(false);
|
||||
const { refetch: refetchQuickFiles } = useQuickFiles(false);
|
||||
const {
|
||||
closeContext,
|
||||
contextSelected,
|
||||
@@ -79,8 +45,17 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
} = props;
|
||||
const { wrapperRef } = useClickOutOfBounds(closeContext);
|
||||
const { isTrash, isMedia } = useUtils();
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
const {
|
||||
renameItem,
|
||||
trashItem,
|
||||
deleteItem,
|
||||
restoreItem,
|
||||
openMoveItemModal,
|
||||
openShareItemModal,
|
||||
downloadItem,
|
||||
selectItemMultiSelect,
|
||||
} = useActions({ quickItemMode });
|
||||
|
||||
useEffect(() => {
|
||||
if (!wrapperRef.current) return;
|
||||
@@ -108,212 +83,54 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
});
|
||||
}, [wrapperRef, contextSelected.X, contextSelected.Y]);
|
||||
|
||||
const renameItem = async () => {
|
||||
const onAction = async (
|
||||
action:
|
||||
| "rename"
|
||||
| "trash"
|
||||
| "delete"
|
||||
| "restore"
|
||||
| "move"
|
||||
| "share"
|
||||
| "download"
|
||||
| "multi-select"
|
||||
) => {
|
||||
closeContext();
|
||||
if (!folderMode && file) {
|
||||
try {
|
||||
const filename = await renameFilePopup(file.filename);
|
||||
if (!filename || filename === file.filename) return;
|
||||
await toast.promise(renameFileAPI(file._id, filename), {
|
||||
pending: "Renaming...",
|
||||
success: "Renamed",
|
||||
error: "Error Renaming",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error renaming file", e);
|
||||
}
|
||||
} else if (folderMode && folder) {
|
||||
try {
|
||||
const folderName = await renameFolderPopup(folder.name);
|
||||
if (!folderName || folderName === folder.name) return;
|
||||
await toast.promise(renameFolder(folder._id, folderName), {
|
||||
pending: "Renaming...",
|
||||
success: "Renamed",
|
||||
error: "Error Renaming",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error renaming folder", e);
|
||||
}
|
||||
switch (action) {
|
||||
case "rename":
|
||||
await renameItem(file, folder);
|
||||
break;
|
||||
case "trash":
|
||||
await trashItem(file, folder);
|
||||
break;
|
||||
case "delete":
|
||||
await deleteItem(file, folder);
|
||||
break;
|
||||
case "restore":
|
||||
await restoreItem(file, folder);
|
||||
break;
|
||||
case "move":
|
||||
await openMoveItemModal(file, folder);
|
||||
break;
|
||||
case "share":
|
||||
openShareItemModal(file);
|
||||
break;
|
||||
case "download":
|
||||
downloadItem(file, folder);
|
||||
break;
|
||||
case "multi-select":
|
||||
selectItemMultiSelect(file, folder);
|
||||
}
|
||||
};
|
||||
|
||||
const trashItem = async () => {
|
||||
closeContext();
|
||||
if (!folderMode && file) {
|
||||
try {
|
||||
const result = await trashItemsPopup();
|
||||
if (!result) return;
|
||||
|
||||
await toast.promise(trashFileAPI(file._id), {
|
||||
pending: "Trashing...",
|
||||
success: "Trashed",
|
||||
error: "Error Trashing",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error trashing file", e);
|
||||
if (
|
||||
folder &&
|
||||
parentBarMode &&
|
||||
["trash", "delete", "restore"].includes(action)
|
||||
) {
|
||||
if (folder.parent === "/") {
|
||||
navigate("/trash");
|
||||
} else {
|
||||
navigate(`/folder-trash/${folder.parent}`);
|
||||
}
|
||||
} else if (folderMode && folder) {
|
||||
try {
|
||||
const result = await trashItemsPopup();
|
||||
if (!result) return;
|
||||
|
||||
await toast.promise(trashFolderAPI(folder._id), {
|
||||
pending: "Trashing...",
|
||||
success: "Trashed",
|
||||
error: "Error Trashing",
|
||||
});
|
||||
reloadItems();
|
||||
|
||||
if (parentBarMode) {
|
||||
if (folder.parent === "/") {
|
||||
navigate("/home");
|
||||
} else {
|
||||
navigate(`/folder/${folder.parent}`);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error trashing folder", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteItem = async () => {
|
||||
closeContext();
|
||||
if (!folderMode && file) {
|
||||
try {
|
||||
const result = await deleteFilePopup();
|
||||
if (!result) return;
|
||||
|
||||
await toast.promise(deleteFileAPI(file._id), {
|
||||
pending: "Deleting...",
|
||||
success: "Deleted",
|
||||
error: "Error Deleting",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error deleting file", e);
|
||||
}
|
||||
} else if (folderMode && folder) {
|
||||
try {
|
||||
const result = await deleteFolderPopup();
|
||||
if (!result) return;
|
||||
|
||||
await toast.promise(deleteFolderAPI(folder._id), {
|
||||
pending: "Deleting...",
|
||||
success: "Deleted",
|
||||
error: "Error Deleting",
|
||||
});
|
||||
reloadItems();
|
||||
|
||||
if (parentBarMode) {
|
||||
if (folder.parent === "/") {
|
||||
navigate("/trash");
|
||||
} else {
|
||||
navigate(`/folder-trash/${folder.parent}`);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error deleting folder", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const restoreItem = async () => {
|
||||
closeContext();
|
||||
const result = await restoreItemPopup();
|
||||
if (!result) return;
|
||||
if (!folderMode && file) {
|
||||
try {
|
||||
await toast.promise(restoreFileAPI(file._id), {
|
||||
pending: "Restoring...",
|
||||
success: "Restored",
|
||||
error: "Error Restoring",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error restoring file", e);
|
||||
}
|
||||
} else if (folderMode && folder) {
|
||||
try {
|
||||
await toast.promise(restoreFolderAPI(folder._id), {
|
||||
pending: "Restoring...",
|
||||
success: "Restored",
|
||||
error: "Error Restoring",
|
||||
});
|
||||
reloadItems();
|
||||
|
||||
if (parentBarMode) {
|
||||
if (folder.parent === "/") {
|
||||
navigate("/trash");
|
||||
} else {
|
||||
navigate(`/folder-trash/${folder.parent}`);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error restoring folder", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const reloadItems = () => {
|
||||
refetchFiles();
|
||||
refetchQuickFiles();
|
||||
refetchFolders();
|
||||
refetchFolder();
|
||||
dispatch(resetSelected());
|
||||
};
|
||||
|
||||
const openMoveItemModal = async () => {
|
||||
closeContext();
|
||||
if (!folderMode && file) {
|
||||
// dispatch(setMoverID(file._id, file.metadata.parent, true));
|
||||
dispatch(setMoveModal({ type: "file", file, folder: null }));
|
||||
} else if (folderMode && folder) {
|
||||
// dispatch(setMoverID(folder._id, folder.parent, false));
|
||||
// }
|
||||
dispatch(setMoveModal({ type: "folder", file: null, folder }));
|
||||
}
|
||||
};
|
||||
|
||||
const openShareItemModal = () => {
|
||||
closeContext();
|
||||
dispatch(setShareModal(file!));
|
||||
};
|
||||
|
||||
const downloadItem = () => {
|
||||
closeContext();
|
||||
if (file) downloadFileAPI(file._id);
|
||||
if (folder) downloadZIPAPI([folder._id], []);
|
||||
};
|
||||
|
||||
const selectItemMultiSelect = () => {
|
||||
closeContext();
|
||||
|
||||
if (folderMode && folder) {
|
||||
dispatch(
|
||||
setMultiSelectMode([
|
||||
{
|
||||
type: "folder",
|
||||
id: folder._id,
|
||||
file: null,
|
||||
folder: folder,
|
||||
},
|
||||
])
|
||||
);
|
||||
} else if (!folderMode && file) {
|
||||
dispatch(
|
||||
setMultiSelectMode([
|
||||
{
|
||||
type: quickItemMode ? "quick-item" : "file",
|
||||
id: file._id,
|
||||
file: file,
|
||||
folder: null,
|
||||
},
|
||||
])
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -348,7 +165,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
<div>
|
||||
{!parentBarMode && (
|
||||
<div
|
||||
onClick={selectItemMultiSelect}
|
||||
onClick={() => onAction("multi-select")}
|
||||
className="text-gray-primary flex flex-row p-4 hover:bg-white-hover hover:text-primary rounded-t-md"
|
||||
>
|
||||
<MultiSelectIcon className="w-5 h-5" />
|
||||
@@ -357,7 +174,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
)}
|
||||
{!isTrash && !isMedia && (
|
||||
<div
|
||||
onClick={renameItem}
|
||||
onClick={() => onAction("rename")}
|
||||
className="text-gray-primary flex flex-row p-4 hover:bg-white-hover hover:text-primary"
|
||||
>
|
||||
<RenameIcon className="w-5 h-5" />
|
||||
@@ -366,7 +183,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
)}
|
||||
{!folderMode && !isTrash && (
|
||||
<div
|
||||
onClick={openShareItemModal}
|
||||
onClick={() => onAction("share")}
|
||||
className="text-gray-primary flex flex-row p-4 hover:bg-white-hover hover:text-primary"
|
||||
>
|
||||
<ShareIcon className="w-5 h-5" />
|
||||
@@ -375,7 +192,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
)}
|
||||
{!isTrash && (
|
||||
<div
|
||||
onClick={downloadItem}
|
||||
onClick={() => onAction("download")}
|
||||
className="text-gray-primary flex flex-row p-4 hover:bg-white-hover hover:text-primary"
|
||||
>
|
||||
<DownloadIcon className="w-5 h-5" />
|
||||
@@ -384,7 +201,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
)}
|
||||
{!isTrash && !isMedia && (
|
||||
<div
|
||||
onClick={openMoveItemModal}
|
||||
onClick={() => onAction("move")}
|
||||
className="text-gray-primary flex flex-row p-4 hover:bg-white-hover hover:text-primary"
|
||||
>
|
||||
<MoveIcon className="w-5 h-5" />
|
||||
@@ -393,7 +210,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
)}
|
||||
{!isTrash && (
|
||||
<div
|
||||
onClick={trashItem}
|
||||
onClick={() => onAction("trash")}
|
||||
className="text-gray-primary flex flex-row p-4 hover:bg-white-hover hover:text-primary rounded-b-md"
|
||||
>
|
||||
<TrashIcon className="w-5 h-5" />
|
||||
@@ -402,7 +219,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
)}
|
||||
{isTrash && (
|
||||
<div
|
||||
onClick={restoreItem}
|
||||
onClick={() => onAction("restore")}
|
||||
className="text-gray-primary flex flex-row p-4 hover:bg-white-hover hover:text-primary"
|
||||
>
|
||||
<RestoreIcon className="w-5 h-5" />
|
||||
@@ -411,7 +228,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
)}
|
||||
{isTrash && (
|
||||
<div
|
||||
onClick={deleteItem}
|
||||
onClick={() => onAction("delete")}
|
||||
className="text-gray-primary flex flex-row p-4 hover:bg-white-hover hover:text-red-500 rounded-b-md"
|
||||
>
|
||||
<TrashIcon className="w-5 h-5" />
|
||||
|
||||
@@ -118,8 +118,8 @@ const DataForm = memo(
|
||||
|
||||
{isTrash && (
|
||||
<div
|
||||
className="bg-primary p-4 rounded-md text-sm
|
||||
text-white mt-4 flex items-center select-none"
|
||||
className="bg-light-primary p-4 rounded-md text-sm
|
||||
text-black mt-4 flex items-center select-none"
|
||||
>
|
||||
<AlertIcon className="w-6 h-6 min-h-6 min-w-6 mr-2" />
|
||||
<span>
|
||||
|
||||
@@ -13,6 +13,8 @@ import ActionsIcon from "../../icons/ActionsIcon";
|
||||
import { FileInterface } from "../../types/file";
|
||||
import getBackendURL from "../../utils/getBackendURL";
|
||||
import dayjs from "dayjs";
|
||||
import CalendarIcon from "../../icons/CalendarIcon";
|
||||
import ClockIcon from "../../icons/ClockIcon";
|
||||
|
||||
interface FileItemProps {
|
||||
file: FileInterface;
|
||||
@@ -168,7 +170,7 @@ const FileItem: React.FC<FileItemProps> = 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-[130px] sm:h-[150px] animiate hover:border-primary overflow-hidden bg-white ",
|
||||
"border rounded-md o transition-all duration-400 ease-in-out cursor-pointer flex items-center justify-center flex-col h-[150px] animiate hover:border-primary overflow-hidden bg-white ",
|
||||
elementSelected || elementMultiSelected
|
||||
? "border-primary"
|
||||
: "border-gray-third"
|
||||
@@ -250,7 +252,7 @@ const FileItem: React.FC<FileItemProps> = memo((props) => {
|
||||
>
|
||||
<p
|
||||
className={classNames(
|
||||
"text-[14px] leading-[16px] font-normal max-w-full overflow-hidden text-ellipsis whitespace-nowrap animate mb-1 sm:mb-0",
|
||||
"text-[14px] leading-[16px] font-normal max-w-full overflow-hidden text-ellipsis whitespace-nowrap animate mb-0",
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-[#212b36]"
|
||||
@@ -258,16 +260,19 @@ const FileItem: React.FC<FileItemProps> = memo((props) => {
|
||||
>
|
||||
{formattedFilename}
|
||||
</p>
|
||||
<span
|
||||
className={classNames(
|
||||
"m-0 font-normal max-w-full whitespace-nowrap text-xs animate hidden sm:block mt-1",
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-gray-primary]"
|
||||
)}
|
||||
>
|
||||
Created {formattedCreatedDate}
|
||||
</span>
|
||||
<div className="flex flex-row items-center mt-2">
|
||||
<ClockIcon className="h-4 w-4 mr-1" />
|
||||
<p
|
||||
className={classNames(
|
||||
"m-0 font-normal max-w-full whitespace-nowrap text-xs animate block",
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-gray-primary]"
|
||||
)}
|
||||
>
|
||||
{formattedCreatedDate}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
import { useUtils } from "../../hooks/utils";
|
||||
import { FolderInterface } from "../../types/folders";
|
||||
import dayjs from "dayjs";
|
||||
import ClockIcon from "../../icons/ClockIcon";
|
||||
|
||||
interface FolderItemProps {
|
||||
folder: FolderInterface;
|
||||
@@ -163,16 +164,19 @@ const FolderItem: React.FC<FolderItemProps> = memo((props) => {
|
||||
>
|
||||
{folder.name}
|
||||
</p>
|
||||
<span
|
||||
className={classNames(
|
||||
"m-0 font-normal max-w-full whitespace-nowrap text-xs animate hidden sm:block mt-1",
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-gray-primary"
|
||||
)}
|
||||
>
|
||||
Created {dayjs(folder.createdAt).format("MM/DD/YY hh:mma")}
|
||||
</span>
|
||||
<div className="flex flex-row items-center mt-1">
|
||||
<ClockIcon className="h-4 w-4 mr-1" />
|
||||
<p
|
||||
className={classNames(
|
||||
"m-0 font-normal max-w-full whitespace-nowrap text-xs animate",
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-gray-primary"
|
||||
)}
|
||||
>
|
||||
{dayjs(folder.createdAt).format("MM/DD/YY hh:mma")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -111,7 +111,7 @@ const LeftSection = ({
|
||||
}
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-col h-full select-none">
|
||||
<div className="flex flex-col h-full select-none text-sm">
|
||||
<div>
|
||||
<div className="relative mb-7">
|
||||
<a
|
||||
@@ -148,7 +148,7 @@ const LeftSection = ({
|
||||
onClick={goMedia}
|
||||
>
|
||||
<PhotoIcon className="w-6 h-6" />
|
||||
<p className="ml-3">Media</p>
|
||||
<p className="ml-2.5">Media</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -159,7 +159,7 @@ const LeftSection = ({
|
||||
onClick={goSettings}
|
||||
>
|
||||
<SettingsIcon className="w-6 h-6" />
|
||||
<p className="ml-3">Settings</p>
|
||||
<p className="ml-2.5">Settings</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -170,7 +170,7 @@ const LeftSection = ({
|
||||
onClick={goTrash}
|
||||
>
|
||||
<TrashIcon className="w-6 h-6" />
|
||||
<p className="ml-3">Trash</p>
|
||||
<p className="ml-2.5">Trash</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -86,7 +86,7 @@ const MediaItem: React.FC<MediaItemType> = memo(({ file }) => {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"h-[100px] bg-black overflow-hidden rounded-md cursor-pointer relative",
|
||||
"h-[100px] bg-black overflow-hidden cursor-pointer relative",
|
||||
{
|
||||
"border-4 border-[#3c85ee]": elementSelected || elementMultiSelected,
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ const Medias = memo(
|
||||
{!isLoadingFiles && (
|
||||
<div
|
||||
className={classNames(
|
||||
"grid grid-cols-[repeat(auto-fill,minmax(100px,1fr))] gap-[10px]"
|
||||
"grid grid-cols-[repeat(auto-fill,minmax(100px,1fr))] gap-[2px]"
|
||||
)}
|
||||
>
|
||||
<div className="fixed bottom-0 flex justify-center items-center right-0 left-0 z-10">
|
||||
|
||||
@@ -35,8 +35,8 @@ const QuickAccess = memo(() => {
|
||||
? "justify-normal"
|
||||
: "justify-center xs:justify-normal",
|
||||
{
|
||||
"max-h-36 sm:max-h-40": !quickAccessExpanded,
|
||||
"max-h-[720px] sm:max-h-[665px] quickAccessOne:max-h-[1000px] quickAccessTwo:max-h-[660px] quickAccessThree:max-h-[490px]":
|
||||
"max-h-40": !quickAccessExpanded,
|
||||
"max-h-[655px] quickAccessOne:max-h-[990px] quickAccessTwo:max-h-[660px] quickAccessThree:max-h-[490px]":
|
||||
quickAccessExpanded,
|
||||
}
|
||||
)}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import PlayButtonIcon from "../../icons/PlayIcon";
|
||||
import dayjs from "dayjs";
|
||||
import getBackendURL from "../../utils/getBackendURL";
|
||||
import ClockIcon from "../../icons/ClockIcon";
|
||||
|
||||
interface QuickAccessItemProps {
|
||||
file: FileInterface;
|
||||
@@ -98,7 +99,7 @@ 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-[130px] sm:h-[150px] animiate hover:border-[#3c85ee] overflow-hidden bg-white",
|
||||
"border rounded-md o transition-all duration-400 ease-in-out cursor-pointer flex items-center justify-center flex-col h-[150px] animiate hover:border-[#3c85ee] overflow-hidden bg-white",
|
||||
elementSelected || elementMultiSelected
|
||||
? "border-[#3c85ee]"
|
||||
: "border-gray-third"
|
||||
@@ -180,7 +181,7 @@ const QuickAccessItem = memo((props: QuickAccessItemProps) => {
|
||||
>
|
||||
<p
|
||||
className={classNames(
|
||||
"text-[14px] leading-[16px] font-normal max-w-full overflow-hidden text-ellipsis whitespace-nowrap animate mb-1 sm:mb-0",
|
||||
"text-[14px] leading-[16px] font-normal max-w-full overflow-hidden text-ellipsis whitespace-nowrap animate mb-0",
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-[#212b36]"
|
||||
@@ -188,16 +189,19 @@ const QuickAccessItem = memo((props: QuickAccessItemProps) => {
|
||||
>
|
||||
{formattedFilename}
|
||||
</p>
|
||||
<span
|
||||
className={classNames(
|
||||
"text-[#637381] font-normal max-w-full whitespace-nowrap text-xs animate hidden sm:block mt-1",
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-[#637381]"
|
||||
)}
|
||||
>
|
||||
Created {formattedDate}
|
||||
</span>
|
||||
<div className="flex flex-row items-center mt-2">
|
||||
<ClockIcon className="h-4 w-4 mr-1" />
|
||||
<p
|
||||
className={classNames(
|
||||
"m-0 font-normal max-w-full whitespace-nowrap text-xs animate",
|
||||
elementSelected || elementMultiSelected
|
||||
? "text-white"
|
||||
: "text-gray-primary]"
|
||||
)}
|
||||
>
|
||||
{formattedDate}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -8,10 +8,56 @@ import { resetSelected } from "../../reducers/selected";
|
||||
import CloseIcon from "../../icons/CloseIcon";
|
||||
import FileDetailsIcon from "../../icons/FileDetailsIcon";
|
||||
import dayjs from "dayjs";
|
||||
import DownloadIcon from "../../icons/DownloadIcon";
|
||||
import ShareIcon from "../../icons/ShareIcon";
|
||||
import TrashIcon from "../../icons/TrashIcon";
|
||||
import RenameIcon from "../../icons/RenameIcon";
|
||||
import { useActions } from "../../hooks/actions";
|
||||
import RestoreIcon from "../../icons/RestoreIcon";
|
||||
|
||||
const RightSection = memo(() => {
|
||||
const selectedItem = useAppSelector((state) => state.selected.mainSection);
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
renameItem,
|
||||
trashItem,
|
||||
deleteItem,
|
||||
restoreItem,
|
||||
openShareItemModal,
|
||||
downloadItem,
|
||||
} = useActions({
|
||||
quickItemMode: false,
|
||||
});
|
||||
|
||||
const onAction = async (
|
||||
action: "rename" | "trash" | "delete" | "restore" | "download" | "share"
|
||||
) => {
|
||||
const file = selectedItem.file;
|
||||
const folder = selectedItem.folder;
|
||||
|
||||
switch (action) {
|
||||
case "rename":
|
||||
await renameItem(file, folder);
|
||||
break;
|
||||
case "trash":
|
||||
await trashItem(file, folder);
|
||||
break;
|
||||
case "delete":
|
||||
await deleteItem(file, folder);
|
||||
break;
|
||||
case "restore":
|
||||
await restoreItem(file, folder);
|
||||
break;
|
||||
case "download":
|
||||
downloadItem(file, folder);
|
||||
break;
|
||||
case "share":
|
||||
openShareItemModal(file);
|
||||
}
|
||||
};
|
||||
|
||||
const itemTrashed =
|
||||
selectedItem?.file?.metadata.trashed || selectedItem?.folder?.trashed;
|
||||
|
||||
const formattedName = useMemo(() => {
|
||||
if (!selectedItem.id) return "";
|
||||
@@ -81,79 +127,131 @@ const RightSection = memo(() => {
|
||||
>
|
||||
{selectedItem.id === "" ? (
|
||||
<div className="flex flex-col justify-center items-center text-center">
|
||||
<FileDetailsIcon />
|
||||
<p className="text-[#637381] text-[16px] leading-[24px] font-normal m-0 mt-[30px]">
|
||||
<FileDetailsIcon className="w-10 h-10" />
|
||||
<p className="text-gray-500 text-xs mt-4">
|
||||
Select a file or folder to view it’s details
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full">
|
||||
<div className="flex flex-row">
|
||||
<div></div>
|
||||
<div className="w-full h-16 flex items-center relative">
|
||||
<div
|
||||
className="opacity-40 w-full h-full absolute"
|
||||
style={{ background: bannerBackgroundColor }}
|
||||
></div>
|
||||
<p className="text-sm ml-6 z-10">{bannerText}</p>
|
||||
<div className="w-full flex flex-col justify-between">
|
||||
<div>
|
||||
<div className="flex flex-row">
|
||||
<div></div>
|
||||
<div className="w-full h-16 flex items-center relative">
|
||||
<div
|
||||
className="opacity-40 w-full h-full absolute"
|
||||
style={{ background: bannerBackgroundColor }}
|
||||
></div>
|
||||
<p className="text-sm ml-6 z-10">{bannerText}</p>
|
||||
</div>
|
||||
<CloseIcon
|
||||
className="w-5 h-5 p-1 cursor-pointer absolute right-3 top-5 bg-white rounded-full shadow-lg z-10"
|
||||
onClick={reset}
|
||||
/>
|
||||
</div>
|
||||
<CloseIcon
|
||||
className="w-5 h-5 p-1 cursor-pointer absolute right-3 top-5 bg-white rounded-full shadow-lg z-10"
|
||||
onClick={reset}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
<div className="mb-5">
|
||||
<p className="m-0 text-[#212b36] text-[16px] font-bold max-h-[90px] overflow-hidden text-ellipsis block break-all">
|
||||
<div className="p-6">
|
||||
<p className="m-0 text-[#212b36] text-sm font-bold max-h-[90px] overflow-hidden text-ellipsis block break-all">
|
||||
{formattedName}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex mb-[7px] justify-start">
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Type
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{selectedItem.file ? fileExtension : "Folder"}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="flex mb-[7px] justify-start"
|
||||
style={
|
||||
!selectedItem.file ? { display: "none" } : { display: "flex" }
|
||||
}
|
||||
>
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Size
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{fileSize}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex mb-[7px] justify-start">
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Created
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{formattedDate}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="flex mb-[7px] justify-start"
|
||||
style={
|
||||
!selectedItem.file ? { display: "none" } : { display: "flex" }
|
||||
}
|
||||
>
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Access
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{selectedItem.file?.metadata.link ? "Public" : "Private"}
|
||||
</span>
|
||||
|
||||
<div className="p-6 pt-0">
|
||||
<p className="text-sm mb-4">Information</p>
|
||||
<div className="flex flex-col space-y-2">
|
||||
<div className="flex justify-between border-b border-gray-200 pb-2">
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Type
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{selectedItem.file ? fileExtension : "Folder"}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="flex justify-between border-b border-gray-200 pb-2"
|
||||
style={
|
||||
!selectedItem.file
|
||||
? { display: "none" }
|
||||
: { display: "flex" }
|
||||
}
|
||||
>
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Size
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{fileSize}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between border-b border-gray-200 pb-2">
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Created
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{formattedDate}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="flex justify-between border-b border-gray-200 pb-2"
|
||||
style={
|
||||
!selectedItem.file
|
||||
? { display: "none" }
|
||||
: { display: "flex" }
|
||||
}
|
||||
>
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Access
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{selectedItem.file?.metadata.link ? "Public" : "Private"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* <div
|
||||
className="w-full p-0.5 opacity-40 h-10 absolute bottom-0"
|
||||
style={{ background: bannerBackgroundColor }}
|
||||
></div>
|
||||
<div className="flex flex-row justify-between w-full z-10">
|
||||
{!itemTrashed && (
|
||||
<div
|
||||
className="text-gray-600 hover:text-black p-2.5 rounded-full flex items-center justify-center cursor-pointer"
|
||||
onClick={() => onAction("download")}
|
||||
>
|
||||
<DownloadIcon className="w-5 h-5" />
|
||||
</div>
|
||||
)}
|
||||
{selectedItem.file && !itemTrashed && (
|
||||
<div
|
||||
className="text-gray-600 hover:text-black p-2.5 rounded-full flex items-center justify-center cursor-pointer"
|
||||
onClick={() => onAction("share")}
|
||||
>
|
||||
<ShareIcon className="w-5 h-5" />
|
||||
</div>
|
||||
)}
|
||||
{itemTrashed && (
|
||||
<div
|
||||
className="text-gray-600 hover:text-black p-2.5 rounded-full flex items-center justify-center cursor-pointer"
|
||||
onClick={() => onAction("restore")}
|
||||
>
|
||||
<RestoreIcon className="w-5 h-5" />
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="text-gray-600 hover:text-black p-2.5 rounded-full flex items-center justify-center cursor-pointer"
|
||||
onClick={() => onAction(itemTrashed ? "delete" : "trash")}
|
||||
>
|
||||
<TrashIcon className="w-5 h-5" />
|
||||
</div>
|
||||
{!itemTrashed && (
|
||||
<div
|
||||
className="text-gray-600 hover:text-black p-2.5 rounded-full flex items-center justify-center cursor-pointer"
|
||||
onClick={() => onAction("rename")}
|
||||
>
|
||||
<RenameIcon className="w-5 h-5" />
|
||||
</div>
|
||||
)}
|
||||
</div> */}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
import { toast } from "react-toastify";
|
||||
import {
|
||||
deleteFileAPI,
|
||||
downloadFileAPI,
|
||||
renameFileAPI,
|
||||
restoreFileAPI,
|
||||
trashFileAPI,
|
||||
} from "../api/filesAPI";
|
||||
import {
|
||||
deleteFilePopup,
|
||||
renameFilePopup,
|
||||
restoreItemPopup,
|
||||
trashItemsPopup,
|
||||
} from "../popups/file";
|
||||
import { FileInterface } from "../types/file";
|
||||
import { FolderInterface } from "../types/folders";
|
||||
import { useFiles, useQuickFiles } from "./files";
|
||||
import { useFolder, useFolders } from "./folders";
|
||||
import { useAppDispatch } from "./store";
|
||||
import {
|
||||
resetSelected,
|
||||
setMoveModal,
|
||||
setMultiSelectMode,
|
||||
setShareModal,
|
||||
} from "../reducers/selected";
|
||||
import { deleteFolderPopup, renameFolderPopup } from "../popups/folder";
|
||||
import {
|
||||
deleteFolderAPI,
|
||||
downloadZIPAPI,
|
||||
renameFolder,
|
||||
restoreFolderAPI,
|
||||
trashFolderAPI,
|
||||
} from "../api/foldersAPI";
|
||||
|
||||
type UseActionsProps = {
|
||||
quickItemMode?: boolean;
|
||||
};
|
||||
|
||||
export const useActions = ({ quickItemMode }: UseActionsProps) => {
|
||||
const { refetch: refetchFiles } = useFiles(false);
|
||||
const { refetch: refetchFolders } = useFolders(false);
|
||||
const { refetch: refetchFolder } = useFolder(false);
|
||||
const { refetch: refetchQuickFiles } = useQuickFiles(false);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const reloadItems = () => {
|
||||
refetchFiles();
|
||||
refetchQuickFiles();
|
||||
refetchFolders();
|
||||
refetchFolder();
|
||||
dispatch(resetSelected());
|
||||
};
|
||||
|
||||
const renameItem = async (
|
||||
file?: FileInterface | null,
|
||||
folder?: FolderInterface | null
|
||||
) => {
|
||||
if (file) {
|
||||
try {
|
||||
const filename = await renameFilePopup(file.filename);
|
||||
if (!filename || filename === file.filename) return;
|
||||
await toast.promise(renameFileAPI(file._id, filename), {
|
||||
pending: "Renaming...",
|
||||
success: "Renamed",
|
||||
error: "Error Renaming",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error renaming file", e);
|
||||
}
|
||||
} else if (folder) {
|
||||
try {
|
||||
const folderName = await renameFolderPopup(folder.name);
|
||||
if (!folderName || folderName === folder.name) return;
|
||||
await toast.promise(renameFolder(folder._id, folderName), {
|
||||
pending: "Renaming...",
|
||||
success: "Renamed",
|
||||
error: "Error Renaming",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error renaming folder", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const trashItem = async (
|
||||
file?: FileInterface | null,
|
||||
folder?: FolderInterface | null
|
||||
) => {
|
||||
if (file) {
|
||||
try {
|
||||
const result = await trashItemsPopup();
|
||||
if (!result) return;
|
||||
|
||||
await toast.promise(trashFileAPI(file._id), {
|
||||
pending: "Trashing...",
|
||||
success: "Trashed",
|
||||
error: "Error Trashing",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error trashing file", e);
|
||||
}
|
||||
} else if (folder) {
|
||||
try {
|
||||
const result = await trashItemsPopup();
|
||||
if (!result) return;
|
||||
|
||||
await toast.promise(trashFolderAPI(folder._id), {
|
||||
pending: "Trashing...",
|
||||
success: "Trashed",
|
||||
error: "Error Trashing",
|
||||
});
|
||||
reloadItems();
|
||||
|
||||
// if (parentBarMode) {
|
||||
// if (folder.parent === "/") {
|
||||
// navigate("/home");
|
||||
// } else {
|
||||
// navigate(`/folder/${folder.parent}`);
|
||||
// }
|
||||
// }
|
||||
} catch (e) {
|
||||
console.log("Error trashing folder", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteItem = async (
|
||||
file?: FileInterface | null,
|
||||
folder?: FolderInterface | null
|
||||
) => {
|
||||
if (file) {
|
||||
try {
|
||||
const result = await deleteFilePopup();
|
||||
if (!result) return;
|
||||
|
||||
await toast.promise(deleteFileAPI(file._id), {
|
||||
pending: "Deleting...",
|
||||
success: "Deleted",
|
||||
error: "Error Deleting",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error deleting file", e);
|
||||
}
|
||||
} else if (folder) {
|
||||
try {
|
||||
const result = await deleteFolderPopup();
|
||||
if (!result) return;
|
||||
|
||||
await toast.promise(deleteFolderAPI(folder._id), {
|
||||
pending: "Deleting...",
|
||||
success: "Deleted",
|
||||
error: "Error Deleting",
|
||||
});
|
||||
reloadItems();
|
||||
|
||||
// if (parentBarMode) {
|
||||
// if (folder.parent === "/") {
|
||||
// navigate("/trash");
|
||||
// } else {
|
||||
// navigate(`/folder-trash/${folder.parent}`);
|
||||
// }
|
||||
// }
|
||||
} catch (e) {
|
||||
console.log("Error deleting folder", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const restoreItem = async (
|
||||
file?: FileInterface | null,
|
||||
folder?: FolderInterface | null
|
||||
) => {
|
||||
const result = await restoreItemPopup();
|
||||
if (!result) return;
|
||||
if (file) {
|
||||
try {
|
||||
await toast.promise(restoreFileAPI(file._id), {
|
||||
pending: "Restoring...",
|
||||
success: "Restored",
|
||||
error: "Error Restoring",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error restoring file", e);
|
||||
}
|
||||
} else if (folder) {
|
||||
try {
|
||||
await toast.promise(restoreFolderAPI(folder._id), {
|
||||
pending: "Restoring...",
|
||||
success: "Restored",
|
||||
error: "Error Restoring",
|
||||
});
|
||||
reloadItems();
|
||||
} catch (e) {
|
||||
console.log("Error restoring folder", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const openMoveItemModal = async (
|
||||
file?: FileInterface | null,
|
||||
folder?: FolderInterface | null
|
||||
) => {
|
||||
if (file) {
|
||||
dispatch(setMoveModal({ type: "file", file, folder: null }));
|
||||
} else if (folder) {
|
||||
dispatch(setMoveModal({ type: "folder", file: null, folder }));
|
||||
}
|
||||
};
|
||||
|
||||
const openShareItemModal = (file?: FileInterface | null) => {
|
||||
dispatch(setShareModal(file!));
|
||||
};
|
||||
|
||||
const downloadItem = (
|
||||
file?: FileInterface | null,
|
||||
folder?: FolderInterface | null
|
||||
) => {
|
||||
if (file) downloadFileAPI(file._id);
|
||||
if (folder) downloadZIPAPI([folder._id], []);
|
||||
};
|
||||
|
||||
const selectItemMultiSelect = (
|
||||
file?: FileInterface | null,
|
||||
folder?: FolderInterface | null
|
||||
) => {
|
||||
if (folder) {
|
||||
dispatch(
|
||||
setMultiSelectMode([
|
||||
{
|
||||
type: "folder",
|
||||
id: folder._id,
|
||||
file: null,
|
||||
folder: folder,
|
||||
},
|
||||
])
|
||||
);
|
||||
} else if (file) {
|
||||
dispatch(
|
||||
setMultiSelectMode([
|
||||
{
|
||||
type: quickItemMode ? "quick-item" : "file",
|
||||
id: file._id,
|
||||
file: file,
|
||||
folder: null,
|
||||
},
|
||||
])
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
renameItem,
|
||||
trashItem,
|
||||
deleteItem,
|
||||
restoreItem,
|
||||
openMoveItemModal,
|
||||
openShareItemModal,
|
||||
downloadItem,
|
||||
selectItemMultiSelect,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
type ClockIconType = React.SVGAttributes<SVGSVGElement>;
|
||||
|
||||
const ClockIcon: React.FC<ClockIconType> = (props) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
fill="currentColor"
|
||||
>
|
||||
<title>clock-time-eight-outline</title>
|
||||
<path d="M12 20C16.4 20 20 16.4 20 12S16.4 4 12 4 4 7.6 4 12 7.6 20 12 20M12 2C17.5 2 22 6.5 22 12S17.5 22 12 22C6.5 22 2 17.5 2 12C2 6.5 6.5 2 12 2M12.5 12.8L7.7 15.6L7 14.2L11 11.9V7H12.5V12.8Z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default ClockIcon;
|
||||
@@ -18,6 +18,7 @@ export interface FileInterface {
|
||||
filePath?: string;
|
||||
s3ID?: string;
|
||||
personalFile?: boolean;
|
||||
trashed?: boolean;
|
||||
};
|
||||
}
|
||||
interface example {
|
||||
|
||||
@@ -7,4 +7,5 @@ export interface FolderInterface {
|
||||
updatedAt: Date;
|
||||
parentList: string[];
|
||||
personalFolder?: boolean;
|
||||
trashed?: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user