added restore logic and fixed delete and added multi delete
This commit is contained in:
@@ -509,7 +509,7 @@ class FileController {
|
||||
}
|
||||
};
|
||||
|
||||
deleteFile = async (req: RequestType, res: Response) => {
|
||||
restoreFile = async (req: RequestType, res: Response) => {
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
@@ -518,7 +518,26 @@ class FileController {
|
||||
const userID = req.user._id;
|
||||
const fileID = req.body.id;
|
||||
|
||||
console.log("id", fileID);
|
||||
const file = await fileService.restoreFile(userID, fileID);
|
||||
|
||||
res.send(file);
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.log("\nRestore File Error File Route:", e.message);
|
||||
}
|
||||
|
||||
res.status(500).send("Server error restoring file");
|
||||
}
|
||||
};
|
||||
|
||||
deleteFile = async (req: RequestType, res: Response) => {
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const userID = req.user._id;
|
||||
const fileID = req.body.id;
|
||||
|
||||
await this.chunkService.deleteFile(userID, fileID);
|
||||
|
||||
@@ -532,6 +551,29 @@ class FileController {
|
||||
}
|
||||
};
|
||||
|
||||
deleteMulti = async (req: RequestType, res: Response) => {
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const userID = req.user._id;
|
||||
const items = req.body.items;
|
||||
|
||||
console.log("items", req.body);
|
||||
|
||||
await this.chunkService.deleteMulti(userID, items);
|
||||
|
||||
res.send();
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.log("Delete Multi Error File Route:", e.message);
|
||||
}
|
||||
|
||||
res.status(500).send("Server error deleting multi");
|
||||
}
|
||||
};
|
||||
|
||||
trashMulti = async (req: RequestType, res: Response) => {
|
||||
if (!req.user) {
|
||||
return;
|
||||
@@ -552,6 +594,27 @@ class FileController {
|
||||
res.status(500).send("Server error trashing multi");
|
||||
}
|
||||
};
|
||||
|
||||
restoreMulti = async (req: RequestType, res: Response) => {
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const userID = req.user._id;
|
||||
const items = req.body.items;
|
||||
|
||||
await this.chunkService.restoreMulti(userID, items);
|
||||
|
||||
res.send();
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.log("\nRestore Multi Error File Route:", e.message);
|
||||
}
|
||||
|
||||
res.status(500).send("Server error restoring multi");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default FileController;
|
||||
|
||||
@@ -241,6 +241,27 @@ class FolderController {
|
||||
}
|
||||
};
|
||||
|
||||
restoreFolder = async (req: RequestType, res: Response) => {
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const userID = req.user._id;
|
||||
const folderID = req.body.id;
|
||||
|
||||
await folderService.restoreFolder(userID, folderID);
|
||||
|
||||
res.send();
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.log("Restore Folder Error Folder Route:", e.message);
|
||||
}
|
||||
|
||||
res.status(500).send("Server error restore folder");
|
||||
}
|
||||
};
|
||||
|
||||
renameFolder = async (req: RequestType, res: Response) => {
|
||||
if (!req.user) {
|
||||
return;
|
||||
|
||||
@@ -87,6 +87,18 @@ class DbUtil {
|
||||
return result;
|
||||
};
|
||||
|
||||
restoreFile = async (fileID: string, userID: string) => {
|
||||
const result = await File.updateOne(
|
||||
{ _id: new ObjectId(fileID), "metadata.owner": userID },
|
||||
{
|
||||
$set: {
|
||||
"metadata.trashed": null,
|
||||
},
|
||||
}
|
||||
);
|
||||
return result;
|
||||
};
|
||||
|
||||
getFileInfo = async (fileID: string, userID: string) => {
|
||||
//TODO: Using mongoose like this causes the object to be returned in raw form
|
||||
// const file = await File.findOne({
|
||||
@@ -168,6 +180,21 @@ class DbUtil {
|
||||
return result;
|
||||
};
|
||||
|
||||
restoreFilesByParent = async (parentList: string, userID: string) => {
|
||||
const result = await File.updateMany(
|
||||
{
|
||||
"metadata.owner": userID,
|
||||
"metadata.parentList": { $regex: `.*${parentList}.*` }, // REGEX
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
"metadata.trashed": null,
|
||||
},
|
||||
}
|
||||
);
|
||||
return result;
|
||||
};
|
||||
|
||||
renameFile = async (fileID: string, userID: string, title: string) => {
|
||||
const updateFileResponse = await File.findOneAndUpdate(
|
||||
{ _id: new ObjectId(fileID), "metadata.owner": userID },
|
||||
|
||||
@@ -173,6 +173,21 @@ class DbUtil {
|
||||
);
|
||||
return result;
|
||||
};
|
||||
|
||||
restoreFoldersByParent = async (parentList: string[], userID: string) => {
|
||||
const result = await Folder.updateMany(
|
||||
{
|
||||
owner: userID,
|
||||
parentList: { $all: parentList },
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
trashed: null,
|
||||
},
|
||||
}
|
||||
);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export default DbUtil;
|
||||
|
||||
@@ -103,6 +103,10 @@ router.patch("/file-service/trash", auth, fileController.trashFile);
|
||||
|
||||
router.patch("/file-service/trash-multi", auth, fileController.trashMulti);
|
||||
|
||||
router.patch("/file-service/restore", auth, fileController.restoreFile);
|
||||
|
||||
router.patch("/file-service/restore-multi", auth, fileController.restoreMulti);
|
||||
|
||||
router.delete("/file-service/remove-link/:id", auth, fileController.removeLink);
|
||||
|
||||
router.delete(
|
||||
@@ -113,6 +117,8 @@ router.delete(
|
||||
|
||||
router.delete("/file-service/remove", auth, fileController.deleteFile);
|
||||
|
||||
router.delete("/file-service/remove-multi", auth, fileController.deleteMulti);
|
||||
|
||||
router.post(
|
||||
"/file-service/send-share-email",
|
||||
auth,
|
||||
|
||||
@@ -39,6 +39,8 @@ router.patch("/folder-service/move", auth, folderController.moveFolder);
|
||||
|
||||
router.patch("/folder-service/trash", auth, folderController.trashFolder);
|
||||
|
||||
router.patch("/folder-service/restore", auth, folderController.restoreFolder);
|
||||
|
||||
router.get(
|
||||
"/folder-service/subfolder-list-full",
|
||||
auth,
|
||||
|
||||
@@ -39,7 +39,7 @@ export interface FolderInterface
|
||||
parentList: string[];
|
||||
_doc?: any;
|
||||
personalFolder?: boolean;
|
||||
trashed?: boolean;
|
||||
trashed: boolean | null;
|
||||
}
|
||||
|
||||
const Folder = mongoose.model<FolderInterface>("Folder", folderSchema);
|
||||
|
||||
@@ -504,6 +504,60 @@ class FileSystemService implements ChunkInterface {
|
||||
}
|
||||
};
|
||||
|
||||
restoreMulti = async (
|
||||
userID: string,
|
||||
items: {
|
||||
type: "file" | "folder" | "quick-item";
|
||||
id: string;
|
||||
file?: FileInterface;
|
||||
folder?: FolderInterface;
|
||||
}[]
|
||||
) => {
|
||||
const fileList = items.filter(
|
||||
(item) => item.type === "file" || item.type === "quick-item"
|
||||
);
|
||||
const folderList = items
|
||||
.filter((item) => item.type === "folder")
|
||||
.sort((a, b) => {
|
||||
if (!a.folder || !b.folder) return 0;
|
||||
return b.folder.parentList.length - a.folder.parentList.length;
|
||||
});
|
||||
|
||||
for (const file of fileList) {
|
||||
await fileService.restoreFile(userID, file.id);
|
||||
}
|
||||
for (const folder of folderList) {
|
||||
await folderService.restoreFolder(userID, folder.id);
|
||||
}
|
||||
};
|
||||
|
||||
deleteMulti = async (
|
||||
userID: string,
|
||||
items: {
|
||||
type: "file" | "folder" | "quick-item";
|
||||
id: string;
|
||||
file?: FileInterface;
|
||||
folder?: FolderInterface;
|
||||
}[]
|
||||
) => {
|
||||
const fileList = items.filter(
|
||||
(item) => item.type === "file" || item.type === "quick-item"
|
||||
);
|
||||
const folderList = items
|
||||
.filter((item) => item.type === "folder")
|
||||
.sort((a, b) => {
|
||||
if (!a.folder || !b.folder) return 0;
|
||||
return b.folder.parentList.length - a.folder.parentList.length;
|
||||
});
|
||||
|
||||
for (const file of fileList) {
|
||||
await this.deleteFile(userID, file.id);
|
||||
}
|
||||
for (const folder of folderList) {
|
||||
await this.deleteFolder(userID, folder.id);
|
||||
}
|
||||
};
|
||||
|
||||
deleteFile = async (userID: string, fileID: string) => {
|
||||
const file = await dbUtilsFile.getFileInfo(fileID, userID);
|
||||
|
||||
|
||||
@@ -614,6 +614,26 @@ class S3Service implements ChunkInterface {
|
||||
folder?: FolderInterface;
|
||||
}[]
|
||||
) => {};
|
||||
|
||||
restoreMulti = async (
|
||||
userID: string,
|
||||
items: {
|
||||
type: "file" | "folder" | "quick-item";
|
||||
id: string;
|
||||
file?: FileInterface;
|
||||
folder?: FolderInterface;
|
||||
}[]
|
||||
) => {};
|
||||
|
||||
deleteMulti = async (
|
||||
userID: string,
|
||||
items: {
|
||||
type: "file" | "folder" | "quick-item";
|
||||
id: string;
|
||||
file?: FileInterface;
|
||||
folder?: FolderInterface;
|
||||
}[]
|
||||
) => {};
|
||||
}
|
||||
|
||||
export default S3Service;
|
||||
|
||||
@@ -28,9 +28,9 @@ const tempCreateVideoThumbnailFS = (
|
||||
const writeStream = fs.createWriteStream(
|
||||
env.fsDirectory + thumbnailFilename
|
||||
);
|
||||
const tempWriteStream = fs.createWriteStream(
|
||||
env.fsDirectory + "temp/" + thumbnailFilename
|
||||
);
|
||||
|
||||
const tempDirectory = env.fsDirectory + "temp/" + thumbnailFilename;
|
||||
const tempWriteStream = fs.createWriteStream(tempDirectory);
|
||||
const decipher = crypto.createDecipheriv(
|
||||
"aes256",
|
||||
CIPHER_KEY,
|
||||
@@ -49,7 +49,7 @@ const tempCreateVideoThumbnailFS = (
|
||||
|
||||
decryptedReadStream.pipe(tempWriteStream, { end: true });
|
||||
|
||||
ffmpeg(env.fsDirectory + "temp/" + thumbnailFilename, {
|
||||
ffmpeg(tempDirectory, {
|
||||
timeout: 60,
|
||||
})
|
||||
.seek(1)
|
||||
@@ -97,7 +97,9 @@ const tempCreateVideoThumbnailFS = (
|
||||
|
||||
if (!updatedFile) return reject();
|
||||
|
||||
resolve(updatedFile?.toObject());
|
||||
fs.unlink(tempDirectory, (err) => {
|
||||
resolve(updatedFile?.toObject());
|
||||
});
|
||||
})
|
||||
.on("error", (err, _, stderr) => {
|
||||
console.log("error", err, stderr);
|
||||
|
||||
@@ -236,6 +236,12 @@ class MongoFileService {
|
||||
return trashedFile;
|
||||
};
|
||||
|
||||
restoreFile = async (userID: string, fileID: string) => {
|
||||
const restoredFile = await dbUtilsFile.restoreFile(fileID, userID);
|
||||
if (!restoredFile) throw new NotFoundError("Restore File Not Found Error");
|
||||
return restoredFile;
|
||||
};
|
||||
|
||||
renameFile = async (userID: string, fileID: string, title: string) => {
|
||||
const file = await dbUtilsFile.renameFile(fileID, userID, title);
|
||||
|
||||
|
||||
@@ -225,6 +225,21 @@ class FolderService {
|
||||
await utilsFile.trashFilesByParent(parentList.toString(), userID);
|
||||
};
|
||||
|
||||
restoreFolder = async (userID: string, folderID: string) => {
|
||||
const folder = await utilsFolder.getFolderInfo(folderID, userID);
|
||||
|
||||
if (!folder) throw new NotFoundError("Restore Folder Not Found Error");
|
||||
|
||||
folder.trashed = null;
|
||||
await folder.save();
|
||||
|
||||
const parentList = [...folder.parentList, folder._id!.toString()];
|
||||
|
||||
await utilsFolder.restoreFoldersByParent(parentList, userID);
|
||||
|
||||
await utilsFile.restoreFilesByParent(parentList.toString(), userID);
|
||||
};
|
||||
|
||||
moveFolder = async (userID: string, folderID: string, parentID: string) => {
|
||||
let parentList = ["/"];
|
||||
|
||||
|
||||
@@ -113,6 +113,20 @@ export const trashMultiAPI = async (items: any) => {
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const restoreFileAPI = async (fileID: string) => {
|
||||
const response = await axios.patch(`/file-service/restore`, {
|
||||
id: fileID,
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const restoreMultiAPI = async (items: any) => {
|
||||
const response = await axios.patch(`/file-service/restore-multi`, {
|
||||
items,
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const renameFileAPI = async (fileID: string, name: string) => {
|
||||
const response = await axios.patch(`/file-service/rename`, {
|
||||
id: fileID,
|
||||
@@ -130,3 +144,12 @@ export const deleteFileAPI = async (fileID: string) => {
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const deleteMultiAPI = async (items: any) => {
|
||||
const response = await axios.delete(`/file-service/remove-multi`, {
|
||||
data: {
|
||||
items,
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
@@ -56,8 +56,15 @@ export const renameFolder = async (folderID: string, name: string) => {
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const trashFolderAPI = (folderID: string) => {
|
||||
const response = axios.patch("/folder-service/trash", {
|
||||
export const trashFolderAPI = async (folderID: string) => {
|
||||
const response = await axios.patch("/folder-service/trash", {
|
||||
id: folderID,
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const restoreFolderAPI = async (folderID: string) => {
|
||||
const response = await axios.patch("/folder-service/restore", {
|
||||
id: folderID,
|
||||
});
|
||||
return response.data;
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
renameFileAPI,
|
||||
downloadFileAPI,
|
||||
trashFileAPI,
|
||||
restoreFileAPI,
|
||||
} from "../../api/filesAPI";
|
||||
import { useFilesClient, useQuickFilesClient } from "../../hooks/files";
|
||||
import { useFoldersClient } from "../../hooks/folders";
|
||||
@@ -15,6 +16,7 @@ import { setShareSelected } from "../../actions/selectedItem";
|
||||
import {
|
||||
deleteFolder,
|
||||
renameFolder,
|
||||
restoreFolderAPI,
|
||||
trashFolderAPI,
|
||||
} from "../../api/foldersAPI";
|
||||
import { useClickOutOfBounds, useUtils } from "../../hooks/utils";
|
||||
@@ -27,6 +29,7 @@ import ShareIcon from "../../icons/ShareIcon";
|
||||
import DownloadIcon from "../../icons/DownloadIcon";
|
||||
import MoveIcon from "../../icons/MoveIcon";
|
||||
import RestoreIcon from "../../icons/RestoreIcon";
|
||||
import { restoreItemPopup } from "../../popups/file";
|
||||
|
||||
const ContextMenu = (props) => {
|
||||
const { invalidateFilesCache } = useFilesClient();
|
||||
@@ -148,6 +151,19 @@ const ContextMenu = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
const restoreItem = async () => {
|
||||
props.closeContext();
|
||||
const result = await restoreItemPopup();
|
||||
if (!result) return;
|
||||
if (!props.folderMode) {
|
||||
await restoreFileAPI(props.file._id);
|
||||
invalidateFilesCache();
|
||||
} else {
|
||||
await restoreFolderAPI(props.folder._id);
|
||||
invalidateFoldersCache();
|
||||
}
|
||||
};
|
||||
|
||||
const openMoveItemModal = async () => {
|
||||
props.closeContext();
|
||||
if (!props.folderMode) {
|
||||
@@ -268,7 +284,7 @@ const ContextMenu = (props) => {
|
||||
</li>
|
||||
)}
|
||||
{isTrash && (
|
||||
<li onClick={deleteItem} className={liClassname}>
|
||||
<li onClick={restoreItem} className={liClassname}>
|
||||
<a className="flex">
|
||||
<span className={spanClassname}>
|
||||
<RestoreIcon className="w-[19px] h-[20px]" />
|
||||
|
||||
@@ -13,6 +13,7 @@ import { setPopupFile } from "../../actions/popupFile";
|
||||
import bytes from "bytes";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { setMainSelect, setMultiSelectMode } from "../../reducers/selected";
|
||||
import PlayButtonIcon from "../../icons/PlayIcon";
|
||||
|
||||
const FileItem = React.memo((props) => {
|
||||
const { file } = props;
|
||||
@@ -215,11 +216,18 @@ const FileItem = React.memo((props) => {
|
||||
)}
|
||||
>
|
||||
{hasThumbnail ? (
|
||||
<img
|
||||
className="w-full min-h-[88px] max-h-[88px] h-full flex object-cover"
|
||||
src={image}
|
||||
onError={imageOnError}
|
||||
/>
|
||||
<div className="w-full min-h-[88px] max-h-[88px] h-full flex">
|
||||
<img
|
||||
className=" object-cover"
|
||||
src={image}
|
||||
onError={imageOnError}
|
||||
/>
|
||||
{file.metadata.isVideo && (
|
||||
<div className="w-full h-full absolute flex justify-center items-center text-white">
|
||||
<PlayButtonIcon className="w-[50px] h-[50px]" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
import { useMemo } from "react";
|
||||
import React, { useMemo } from "react";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { resetMultiSelect } from "../../reducers/selected";
|
||||
import Swal from "sweetalert2";
|
||||
import { trashMultiAPI } from "../../api/filesAPI";
|
||||
import {
|
||||
deleteMultiAPI,
|
||||
restoreMultiAPI,
|
||||
trashMultiAPI,
|
||||
} from "../../api/filesAPI";
|
||||
import { useFilesClient, useQuickFilesClient } from "../../hooks/files";
|
||||
import { useFoldersClient } from "../../hooks/folders";
|
||||
import TrashIcon from "../../icons/TrashIcon";
|
||||
import Moveicon from "../../icons/MoveIcon";
|
||||
import { deleteItemsPopup, restoreItemsPopup } from "../../popups/file";
|
||||
import RestoreIcon from "../../icons/RestoreIcon";
|
||||
import { useUtils } from "../../hooks/utils";
|
||||
|
||||
const MultiSelectBar = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -21,11 +30,13 @@ const MultiSelectBar = () => {
|
||||
const { invalidateFoldersCache } = useFoldersClient();
|
||||
const { invalidateQuickFilesCache } = useQuickFilesClient();
|
||||
|
||||
const { isTrash } = useUtils();
|
||||
|
||||
const closeMultiSelect = () => {
|
||||
dispatch(resetMultiSelect());
|
||||
};
|
||||
|
||||
const deleteItems = async () => {
|
||||
const trashItems = async () => {
|
||||
const result = await Swal.fire({
|
||||
title: "Move to trash?",
|
||||
text: "Items in the trash will eventually be deleted.",
|
||||
@@ -36,7 +47,7 @@ const MultiSelectBar = () => {
|
||||
confirmButtonText: "Yes",
|
||||
});
|
||||
|
||||
if (result.value) {
|
||||
if (result) {
|
||||
const itemsToTrash = Object.values(multiSelectMap);
|
||||
await trashMultiAPI(itemsToTrash);
|
||||
invalidateFilesCache();
|
||||
@@ -46,6 +57,31 @@ const MultiSelectBar = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const deleteItems = async () => {
|
||||
const result = await deleteItemsPopup();
|
||||
if (result) {
|
||||
const itemsToTrash = Object.values(multiSelectMap);
|
||||
await deleteMultiAPI(itemsToTrash);
|
||||
invalidateFilesCache();
|
||||
invalidateFoldersCache();
|
||||
invalidateQuickFilesCache();
|
||||
closeMultiSelect();
|
||||
}
|
||||
};
|
||||
|
||||
const restoreItems = async () => {
|
||||
const result = await restoreItemsPopup();
|
||||
|
||||
if (result) {
|
||||
const itemsToTrash = Object.values(multiSelectMap);
|
||||
await restoreMultiAPI(itemsToTrash);
|
||||
invalidateFilesCache();
|
||||
invalidateFoldersCache();
|
||||
invalidateQuickFilesCache();
|
||||
closeMultiSelect();
|
||||
}
|
||||
};
|
||||
|
||||
if (!multiSelectMode) return <div></div>;
|
||||
|
||||
return (
|
||||
@@ -62,56 +98,25 @@ const MultiSelectBar = () => {
|
||||
</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"
|
||||
{!isTrash && (
|
||||
<TrashIcon className="ml-4 cursor-pointer" onClick={trashItems} />
|
||||
)}
|
||||
{isTrash && (
|
||||
<React.Fragment>
|
||||
<RestoreIcon
|
||||
className="ml-4 cursor-pointer h-[20px] w-[20px]"
|
||||
onClick={restoreItems}
|
||||
/>
|
||||
<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"
|
||||
<TrashIcon
|
||||
className="ml-4 cursor-pointer text-red-500"
|
||||
onClick={deleteItems}
|
||||
/>
|
||||
<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>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{!isTrash && (
|
||||
<Moveicon className="ml-4 cursor-pointer" onClick={() => {}} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -58,7 +58,7 @@ class PopupWindow extends React.Component {
|
||||
</div>
|
||||
) : (
|
||||
<video
|
||||
className="popup-window__video"
|
||||
className="popup-window__video !max-h-[70vh]"
|
||||
src={this.props.state.video}
|
||||
ref={this.props.video}
|
||||
type="video/mp4"
|
||||
|
||||
@@ -1,244 +1,243 @@
|
||||
import PopupWindow from "./PopupWindow";
|
||||
import {hidePopup} from "../../actions/popupFile"
|
||||
import { hidePopup } from "../../actions/popupFile";
|
||||
import axios from "../../axiosInterceptor";
|
||||
import env from "../../enviroment/envFrontEnd";
|
||||
import {connect} from "react-redux";
|
||||
import { connect } from "react-redux";
|
||||
import React from "react";
|
||||
import { setPhotoID } from "../../actions/photoViewer";
|
||||
import axiosNonInterceptor from "axios";
|
||||
|
||||
class PopupWindowContainer extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.wrapperRef = React.createRef();
|
||||
this.video = React.createRef();
|
||||
this.imageData = "";
|
||||
this.tempToken = "";
|
||||
|
||||
this.wrapperRef = React.createRef();
|
||||
this.video = React.createRef();
|
||||
this.imageData = ""
|
||||
this.tempToken = ""
|
||||
this.state = {
|
||||
image: "/images/cloud-svg.svg",
|
||||
imageClassname: this.props.popupFile.metadata.hasThumbnail
|
||||
? "popup-window__image popup-window popup-window--gone"
|
||||
: "popup-window__image",
|
||||
video: "",
|
||||
spinnerClassname: "popup-window__spinner__wrapper",
|
||||
};
|
||||
}
|
||||
|
||||
this.state = {
|
||||
image: "/images/cloud-svg.svg",
|
||||
imageClassname: this.props.popupFile.metadata.hasThumbnail ? "popup-window__image popup-window popup-window--gone" : "popup-window__image",
|
||||
video: "",
|
||||
spinnerClassname: "popup-window__spinner__wrapper"
|
||||
}
|
||||
getFileExtension = (filename) => {
|
||||
const filenameSplit = filename.split(".");
|
||||
|
||||
if (filenameSplit.length > 1) {
|
||||
const extension = filenameSplit[filenameSplit.length - 1];
|
||||
|
||||
return extension.toUpperCase();
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
};
|
||||
|
||||
getFileExtension = (filename) => {
|
||||
|
||||
const filenameSplit = filename.split(".");
|
||||
|
||||
if (filenameSplit.length > 1) {
|
||||
|
||||
const extension = filenameSplit[filenameSplit.length - 1]
|
||||
|
||||
return extension.toUpperCase();
|
||||
|
||||
} else {
|
||||
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
getThumbnail = () => {
|
||||
|
||||
if (this.getFileExtension(this.props.popupFile.filename).toLowerCase() === "svg") {
|
||||
this.props.popupFile.metadata.hasThumbnail = false;
|
||||
return this.setState(() => {
|
||||
return {
|
||||
...this.state,
|
||||
image: "/images/cloud-svg.svg",
|
||||
imageClassname: "popup-window__image"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const thumbnailID = this.props.popupFile.metadata.drive ? this.props.popupFile._id : this.props.popupFile.metadata.thumbnailID
|
||||
|
||||
const config = {
|
||||
responseType: 'arraybuffer'
|
||||
getThumbnail = () => {
|
||||
if (
|
||||
this.getFileExtension(this.props.popupFile.filename).toLowerCase() ===
|
||||
"svg"
|
||||
) {
|
||||
this.props.popupFile.metadata.hasThumbnail = false;
|
||||
return this.setState(() => {
|
||||
return {
|
||||
...this.state,
|
||||
image: "/images/cloud-svg.svg",
|
||||
imageClassname: "popup-window__image",
|
||||
};
|
||||
|
||||
const isDrive = this.props.popupFile.metadata.drive;
|
||||
const isPersonal = this.props.popupFile.metadata.personalFile;
|
||||
|
||||
const url = isDrive ? `/file-service-google/thumbnail/${thumbnailID}`
|
||||
: !isPersonal ? `/file-service/thumbnail/${thumbnailID}` : `/file-service-personal/thumbnail/${thumbnailID}`;
|
||||
|
||||
axios.get(url, config).then((results) => {
|
||||
|
||||
const imgFile = new Blob([results.data]);
|
||||
const imgUrl = URL.createObjectURL(imgFile);
|
||||
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
image: imgUrl,
|
||||
imageClassname: "popup-window__image popup-window__image--loaded",
|
||||
spinnerClassname: "popup-window__spinner__wrapper popup-window--gone"
|
||||
|
||||
}))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
thumbnailOnError = () => {
|
||||
const thumbnailID = this.props.popupFile.metadata.drive
|
||||
? this.props.popupFile._id
|
||||
: this.props.popupFile.metadata.thumbnailID;
|
||||
|
||||
const config = {
|
||||
responseType: "arraybuffer",
|
||||
};
|
||||
|
||||
const isDrive = this.props.popupFile.metadata.drive;
|
||||
const isPersonal = this.props.popupFile.metadata.personalFile;
|
||||
|
||||
const url = isDrive
|
||||
? `/file-service-google/thumbnail/${thumbnailID}`
|
||||
: !isPersonal
|
||||
? `/file-service/thumbnail/${thumbnailID}`
|
||||
: `/file-service-personal/thumbnail/${thumbnailID}`;
|
||||
|
||||
axios
|
||||
.get(url, config)
|
||||
.then((results) => {
|
||||
const imgFile = new Blob([results.data]);
|
||||
const imgUrl = URL.createObjectURL(imgFile);
|
||||
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
imageClassname: "popup-window__image",
|
||||
spinnerClassname: "popup-window__spinner__wrapper popup-window--gone",
|
||||
image: "/images/cloud-svg.svg"
|
||||
}))
|
||||
...this.state,
|
||||
image: imgUrl,
|
||||
imageClassname: "popup-window__image popup-window__image--loaded",
|
||||
spinnerClassname: "popup-window__spinner__wrapper popup-window--gone",
|
||||
}));
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
thumbnailOnError = () => {
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
imageClassname: "popup-window__image",
|
||||
spinnerClassname: "popup-window__spinner__wrapper popup-window--gone",
|
||||
image: "/images/cloud-svg.svg",
|
||||
}));
|
||||
};
|
||||
|
||||
handleClickOutside = (e) => {
|
||||
if (this.wrapperRef && !this.wrapperRef.current.contains(event.target)) {
|
||||
this.props.dispatch(hidePopup());
|
||||
}
|
||||
};
|
||||
|
||||
handleClickOutside = (e) => {
|
||||
getVideo = () => {
|
||||
// const config = {
|
||||
// headers: {
|
||||
// uuid: window.sessionStorage.getItem("uuid")
|
||||
// }
|
||||
|
||||
if (this.wrapperRef && !this.wrapperRef.current.contains(event.target)) {
|
||||
this.props.dispatch(hidePopup())
|
||||
}
|
||||
}
|
||||
// };
|
||||
|
||||
getVideo = () => {
|
||||
console.log("gettings stream video token");
|
||||
|
||||
// const config = {
|
||||
// headers: {
|
||||
// uuid: window.sessionStorage.getItem("uuid")
|
||||
// }
|
||||
|
||||
// };
|
||||
axios
|
||||
.get("/file-service/download/access-token-stream-video")
|
||||
.then(() => {
|
||||
console.log("stream video got token");
|
||||
|
||||
console.log("gettings stream video token")
|
||||
|
||||
axios.get("/file-service/download/access-token-stream-video").then(() => {
|
||||
// TODO: Fix this
|
||||
const finalUrl = `http://localhost:5173/api/file-service/stream-video/${this.props.popupFile._id}`;
|
||||
|
||||
console.log("stream video got token")
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
video: finalUrl,
|
||||
}));
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("Stream Video Error", e.message);
|
||||
});
|
||||
|
||||
const isDrive = this.props.popupFile.metadata.drive;
|
||||
const isPersonal = this.props.popupFile.metadata.personalFile;
|
||||
|
||||
const finalUrl = isDrive ?
|
||||
`/file-service-google/stream-video/${this.props.popupFile._id}`
|
||||
: !isPersonal ? `/file-service/stream-video/${this.props.popupFile._id}`
|
||||
: `/file-service-personal/stream-video/${this.props.popupFile._id}`
|
||||
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
video: finalUrl
|
||||
}))
|
||||
// axios.get(currentURL +'/file-service/download/get-token-video',config)
|
||||
// .then((response) => {
|
||||
|
||||
}).catch((e) => {
|
||||
console.log("Stream Video Error", e.message);
|
||||
// this.tempToken = response.data.tempToken;
|
||||
|
||||
// const uuidID = window.sessionStorage.getItem("uuid");
|
||||
|
||||
// const isDrive = this.props.popupFile.metadata.drive;
|
||||
// const isPersonal = this.props.popupFile.metadata.personalFile;
|
||||
|
||||
// const finalUrl = isDrive ?
|
||||
// currentURL + `/file-service-google/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
// : !isPersonal ? currentURL + `/file-service/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
// : currentURL + `/file-service-personal/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
|
||||
// this.setState(() => ({
|
||||
// ...this.state,
|
||||
// video: finalUrl
|
||||
// }))
|
||||
|
||||
// }).catch((err) => {
|
||||
// console.log(err)
|
||||
// })
|
||||
};
|
||||
|
||||
componentWillUnmount = () => {
|
||||
document.removeEventListener("mousedown", this.handleClickOutside);
|
||||
|
||||
if (this.props.popupFile.metadata.isVideo) {
|
||||
axios
|
||||
.delete(`/file-service/remove-stream-video-token`)
|
||||
.then(() => {
|
||||
console.log("removed video access token");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
// axios.get(currentURL +'/file-service/download/get-token-video',config)
|
||||
// .then((response) => {
|
||||
|
||||
// this.tempToken = response.data.tempToken;
|
||||
this.video.current.pause();
|
||||
|
||||
// const uuidID = window.sessionStorage.getItem("uuid");
|
||||
|
||||
// const isDrive = this.props.popupFile.metadata.drive;
|
||||
// const isPersonal = this.props.popupFile.metadata.personalFile;
|
||||
|
||||
// const finalUrl = isDrive ?
|
||||
// currentURL + `/file-service-google/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
// : !isPersonal ? currentURL + `/file-service/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
// : currentURL + `/file-service-personal/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
|
||||
// this.setState(() => ({
|
||||
// ...this.state,
|
||||
// video: finalUrl
|
||||
// }))
|
||||
|
||||
// }).catch((err) => {
|
||||
// console.log(err)
|
||||
// })
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
video: "",
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
componentWillUnmount = () => {
|
||||
componentDidMount = () => {
|
||||
document.addEventListener("mousedown", this.handleClickOutside);
|
||||
|
||||
document.removeEventListener('mousedown', this.handleClickOutside);
|
||||
|
||||
if (this.props.popupFile.metadata.isVideo) {
|
||||
|
||||
axios.delete(`/file-service/remove-stream-video-token`).then(() => {
|
||||
|
||||
console.log("removed video access token");
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
|
||||
this.video.current.pause();
|
||||
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
video: ""
|
||||
}))
|
||||
}
|
||||
if (
|
||||
this.props.popupFile.metadata.hasThumbnail &&
|
||||
!this.props.popupFile.metadata.isVideo &&
|
||||
!this.props.popupFile.metadata.drive
|
||||
) {
|
||||
this.getThumbnail();
|
||||
} else if (
|
||||
this.props.popupFile.metadata.drive &&
|
||||
this.props.popupFile.metadata.hasThumbnail &&
|
||||
!this.props.popupFile.metadata.googleDoc &&
|
||||
!this.props.popupFile.metadata.isVideo
|
||||
) {
|
||||
this.getThumbnail();
|
||||
} else if (
|
||||
this.props.popupFile.metadata.drive &&
|
||||
this.props.popupFile.metadata.hasThumbnail &&
|
||||
!this.props.popupFile.metadata.isVideo
|
||||
) {
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
imageClassname: "popup-window__image",
|
||||
spinnerClassname: "popup-window__spinner__wrapper popup-window--gone",
|
||||
image: "/images/cloud-svg.svg",
|
||||
}));
|
||||
} else if (this.props.popupFile.metadata.isVideo) {
|
||||
this.getVideo();
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
hidePopupWindow = () => {
|
||||
this.props.dispatch(hidePopup());
|
||||
};
|
||||
|
||||
document.addEventListener('mousedown', this.handleClickOutside);
|
||||
|
||||
if (this.props.popupFile.metadata.hasThumbnail && !this.props.popupFile.metadata.isVideo && !this.props.popupFile.metadata.drive) {
|
||||
|
||||
this.getThumbnail()
|
||||
|
||||
} else if (this.props.popupFile.metadata.drive && this.props.popupFile.metadata.hasThumbnail && !this.props.popupFile.metadata.googleDoc && !this.props.popupFile.metadata.isVideo) {
|
||||
|
||||
this.getThumbnail();
|
||||
|
||||
} else if (this.props.popupFile.metadata.drive && this.props.popupFile.metadata.hasThumbnail && !this.props.popupFile.metadata.isVideo) {
|
||||
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
imageClassname: "popup-window__image",
|
||||
spinnerClassname: "popup-window__spinner__wrapper popup-window--gone",
|
||||
image: "/images/cloud-svg.svg"
|
||||
}))
|
||||
|
||||
}else if (this.props.popupFile.metadata.isVideo) {
|
||||
|
||||
this.getVideo();
|
||||
}
|
||||
}
|
||||
|
||||
hidePopupWindow = () => {
|
||||
|
||||
this.props.dispatch(hidePopup());
|
||||
}
|
||||
|
||||
setPhotoViewerWindow = () => {
|
||||
|
||||
const isGoogle = this.props.popupFile.metadata.drive
|
||||
const isPersonal = this.props.popupFile.metadata.personalFile;
|
||||
this.props.dispatch(setPhotoID(this.props.popupFile._id, isGoogle, isPersonal))
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return <PopupWindow
|
||||
wrapperRef={this.wrapperRef}
|
||||
video={this.video}
|
||||
hidePopupWindow={this.hidePopupWindow}
|
||||
state={this.state}
|
||||
setPhotoViewerWindow={this.setPhotoViewerWindow}
|
||||
thumbnailOnError={this.thumbnailOnError}
|
||||
{...this.props}
|
||||
/>
|
||||
}
|
||||
setPhotoViewerWindow = () => {
|
||||
const isGoogle = this.props.popupFile.metadata.drive;
|
||||
const isPersonal = this.props.popupFile.metadata.personalFile;
|
||||
this.props.dispatch(
|
||||
setPhotoID(this.props.popupFile._id, isGoogle, isPersonal)
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<PopupWindow
|
||||
wrapperRef={this.wrapperRef}
|
||||
video={this.video}
|
||||
hidePopupWindow={this.hidePopupWindow}
|
||||
state={this.state}
|
||||
setPhotoViewerWindow={this.setPhotoViewerWindow}
|
||||
thumbnailOnError={this.thumbnailOnError}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const connectPropToState = (state) => ({
|
||||
|
||||
popupFile: state.popupFile,
|
||||
})
|
||||
popupFile: state.popupFile,
|
||||
});
|
||||
|
||||
|
||||
export default connect(connectPropToState)(PopupWindowContainer)
|
||||
export default connect(connectPropToState)(PopupWindowContainer);
|
||||
|
||||
@@ -13,6 +13,7 @@ import { setPopupFile } from "../../actions/popupFile";
|
||||
import { FileInterface } from "../../types/file";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { setMainSelect, setMultiSelectMode } from "../../reducers/selected";
|
||||
import PlayButtonIcon from "../../icons/PlayIcon";
|
||||
|
||||
interface QuickAccessItemProps {
|
||||
file: FileInterface;
|
||||
@@ -127,11 +128,14 @@ const QuickAccessItem = memo((props: QuickAccessItemProps) => {
|
||||
)}
|
||||
>
|
||||
{hasThumbnail ? (
|
||||
<img
|
||||
className="w-full min-h-[88px] max-h-[88px] h-full flex object-cover"
|
||||
src={image}
|
||||
onError={imageOnError}
|
||||
/>
|
||||
<div className="w-full min-h-[88px] max-h-[88px] h-full flex">
|
||||
<img className=" object-cover" src={image} onError={imageOnError} />
|
||||
{file.metadata.isVideo && (
|
||||
<div className="w-full h-full absolute flex justify-center items-center text-white">
|
||||
<PlayButtonIcon className="w-[50px] h-[50px]" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
interface MoveiconProps {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const Moveicon = (props: MoveiconProps) => {
|
||||
@@ -11,6 +12,7 @@ const Moveicon = (props: MoveiconProps) => {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={props.className}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
<path
|
||||
id="Combined Shape"
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
interface PlayIconProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const PlayIcon = (props: PlayIconProps) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
className={props.className}
|
||||
>
|
||||
<title>play</title>
|
||||
<path d="M8,5.14V19.14L19,12.14L8,5.14Z" fill="currentColor" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlayIcon;
|
||||
@@ -1,13 +1,15 @@
|
||||
interface RestoreIconProps {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const RestoreIcon = (props: any) => {
|
||||
const RestoreIcon = (props: RestoreIconProps) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
className={props.className}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
<title>restore</title>
|
||||
<path
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
interface TrashIconProps {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const TrashIcon = (props: TrashIconProps) => {
|
||||
@@ -11,6 +12,7 @@ const TrashIcon = (props: TrashIconProps) => {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={props.className}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
<g id="trash">
|
||||
<path
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
export const restoreItemPopup = async () => {
|
||||
const result = await Swal.fire({
|
||||
title: "Restore item?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes",
|
||||
});
|
||||
return result.value;
|
||||
};
|
||||
|
||||
export const restoreItemsPopup = async () => {
|
||||
const result = await Swal.fire({
|
||||
title: "Restore items?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes",
|
||||
});
|
||||
return result.value;
|
||||
};
|
||||
|
||||
export const deleteItemsPopup = async () => {
|
||||
const result = await Swal.fire({
|
||||
title: "Delete items?",
|
||||
text: "You will not be able to recover these items.",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes",
|
||||
});
|
||||
return result.value;
|
||||
};
|
||||
Reference in New Issue
Block a user