From db925a69d26d0010ebf10f78f2af858896e2ba7e Mon Sep 17 00:00:00 2001 From: subnub Date: Mon, 22 Jul 2024 00:43:04 -0400 Subject: [PATCH] added upload changes --- backend/services/ChunkService/index.ts | 4 +- src/api/filesAPI.ts | 35 +++++ src/components/AddNewDropdown/index.tsx | 16 ++- src/components/DownloadPage/DownloadPage.jsx | 33 ----- src/components/DownloadPage/index.jsx | 85 ------------ src/components/DownloadPage/index.tsx | 129 ++++++++++++++++++ src/components/Homepage/index.tsx | 6 +- src/components/PhotoViewerPopup/index.tsx | 5 +- src/components/SharePopup/index.tsx | 2 +- src/components/UploadItem/UploadItem.jsx | 136 ++++++------------- src/components/Uploader/Uploader.jsx | 63 +++++---- src/hooks/files.ts | 90 +++++++++++- src/icons/CheckCircleIcon.tsx | 15 ++ src/reducers/uploader.ts | 56 ++++++++ src/routers/AppRouter.jsx | 2 +- src/store/configureStore.ts | 2 + src/utils/cancelTokenManager.ts | 1 - 17 files changed, 425 insertions(+), 255 deletions(-) delete mode 100644 src/components/DownloadPage/DownloadPage.jsx delete mode 100644 src/components/DownloadPage/index.jsx create mode 100644 src/components/DownloadPage/index.tsx create mode 100644 src/icons/CheckCircleIcon.tsx create mode 100644 src/reducers/uploader.ts diff --git a/backend/services/ChunkService/index.ts b/backend/services/ChunkService/index.ts index 6409776..c46910d 100644 --- a/backend/services/ChunkService/index.ts +++ b/backend/services/ChunkService/index.ts @@ -274,7 +274,9 @@ class StorageService { throw new NotAuthorizedError("File Not Public"); } - await dbUtilsFile.removeOneTimePublicLink(fileID); + if (file.metadata.linkType === "one") { + await dbUtilsFile.removeOneTimePublicLink(fileID); + } const user = (await User.findById(file.metadata.owner)) as UserInterface; diff --git a/src/api/filesAPI.ts b/src/api/filesAPI.ts index bcc5de0..06788c4 100644 --- a/src/api/filesAPI.ts +++ b/src/api/filesAPI.ts @@ -2,6 +2,7 @@ import { QueryFunctionContext } from "react-query"; import axios from "../axiosInterceptor"; import { getUserToken } from "./user"; import { FileInterface } from "../types/file"; +import { AxiosRequestConfig } from "axios"; interface QueryKeyParams { parent: string; @@ -124,6 +125,33 @@ export const getSuggestedListAPI = async ({ return response.data; }; +export const getPublicFileInfoAPI = async ( + fileID: string, + tempToken: string +) => { + const response = await axios.get( + `/file-service/public/info/${fileID}/${tempToken}` + ); + return response.data; +}; + +export const downloadPublicFileAPI = async ( + fileID: string, + tempToken: string +) => { + await getUserToken(); + + // TODO: Change this + const url = `http://localhost:5173/api/file-service/public/download/${fileID}/${tempToken}`; + + const link = document.createElement("a"); + document.body.appendChild(link); + link.href = url; + link.setAttribute("type", "hidden"); + link.setAttribute("download", "true"); + link.click(); +}; + // PATCH export const trashFileAPI = async (fileID: string) => { @@ -202,3 +230,10 @@ export const deleteVideoTokenAPI = async () => { ); return response.data; }; + +// POST +export const uploadFileAPI = async (data: FormData, config: any) => { + const url = "/file-service/upload"; + const response = await axios.post(url, data, config); + return response.data; +}; diff --git a/src/components/AddNewDropdown/index.tsx b/src/components/AddNewDropdown/index.tsx index 204fa90..f6eed52 100644 --- a/src/components/AddNewDropdown/index.tsx +++ b/src/components/AddNewDropdown/index.tsx @@ -5,7 +5,10 @@ import { useClickOutOfBounds } from "../../hooks/utils"; import { showCreateFolderPopup } from "../../popups/folder"; import { useAppDispatch } from "../../hooks/store"; import { startAddFile } from "../../actions/files"; -import { useRef } from "react"; +import { RefObject, useRef } from "react"; +import axiosNonInterceptor from "axios"; +import uuid from "uuid"; +import { useUploader } from "../../hooks/files"; interface AddNewDropdownProps { closeDropdown: () => void; @@ -15,7 +18,8 @@ const AddNewDropdown: React.FC = (props) => { const params = useParams(); const { invalidateFoldersCache } = useFoldersClient(); const { wrapperRef } = useClickOutOfBounds(props.closeDropdown); - const uploadRef = useRef(""); + const uploadRef: RefObject = useRef(null); + const { uploadFiles } = useUploader(); const dispatch = useAppDispatch(); const createFolder = async () => { @@ -35,10 +39,10 @@ const AddNewDropdown: React.FC = (props) => { props.closeDropdown(); console.log("handle upload"); - dispatch(startAddFile(uploadRef.current, params.id)); - if (uploadRef && uploadRef.current) { - uploadRef.current = ""; - } + const files = uploadRef.current?.files; + if (!files) return; + + uploadFiles(files); }; return ( diff --git a/src/components/DownloadPage/DownloadPage.jsx b/src/components/DownloadPage/DownloadPage.jsx deleted file mode 100644 index f0a155a..0000000 --- a/src/components/DownloadPage/DownloadPage.jsx +++ /dev/null @@ -1,33 +0,0 @@ -import Spinner from "../SpinnerLogin"; -import React from "react"; - -const DownloadPage = ({ download, state }) => { - if (state.size === "" && !state.error) { - return ( -
- -
- ); - } - - return ( -
- {!state.error ? ( -
-

{state.title}

-

Type: {state.type}

-

Size: {state.size}

- -
- ) : ( -
-

Unauthorized/Not Found Download

-
- )} -
- ); -}; - -export default DownloadPage; diff --git a/src/components/DownloadPage/index.jsx b/src/components/DownloadPage/index.jsx deleted file mode 100644 index c1b67eb..0000000 --- a/src/components/DownloadPage/index.jsx +++ /dev/null @@ -1,85 +0,0 @@ -import DownloadPage from "./DownloadPage"; -import capitalize from "../../utils/capitalize"; -import axios from "../../axiosInterceptor"; -import bytes from "bytes"; -import React from "react"; - -class DownloadPageContainer extends React.Component { - - constructor(props) { - super(props); - - this.state = { - error: false, - title: "", - type: "", - size: "", - } - - this.isPersonalFile = false; - } - - getFileExtension = (filename) => { - - const filenameSplit = filename.split("."); - - if (filenameSplit.length > 1) { - - const extension = filenameSplit[filenameSplit.length - 1] - - return extension.toUpperCase(); - - } else { - - return "Unknown" - } - - } - - componentDidMount = () => { - - const _id = this.props.match.params.id; - const tempToken = this.props.match.params.tempToken - - axios.get(`/file-service/public/info/${_id}/${tempToken}`).then((results) => { - - const data = results.data; - - const title = capitalize(data.filename); - const size = bytes(data.length); - const type = this.getFileExtension(title); - this.isPersonalFile = results.data.metadata.personalFile; - - this.setState(() => ({ - ...this.state, - title, - type, - size - })) - - }).catch((err) => { - console.log(err) - this.setState(() => ({...this.state, error: true})) - }) - } - - download = () => { - - const _id = this.props.match.params.id; - const tempToken = this.props.match.params.tempToken - const finalUrl = !this.isPersonalFile ? `/file-service/public/download/${_id}/${tempToken}` : `/file-service-personal/public/download/${_id}/${tempToken}`; - - const link = document.createElement('a'); - document.body.appendChild(link); - link.href = finalUrl; - link.setAttribute('type', 'hidden'); - link.click(); - } - - render() { - - return - } -} - -export default DownloadPageContainer; \ No newline at end of file diff --git a/src/components/DownloadPage/index.tsx b/src/components/DownloadPage/index.tsx new file mode 100644 index 0000000..4e2ccc7 --- /dev/null +++ b/src/components/DownloadPage/index.tsx @@ -0,0 +1,129 @@ +import { useCallback, useEffect, useMemo, useState } from "react"; +import { useParams } from "react-router-dom"; +import axios from "../../axiosInterceptor"; +import { + downloadPublicFileAPI, + getPublicFileInfoAPI, +} from "../../api/filesAPI"; +import { toast, ToastContainer } from "react-toastify"; +import SpinnerPage from "../SpinnerPage"; +import moment from "moment"; +import { getFileColor, getFileExtension } from "../../utils/files"; +import { FileInterface } from "../../types/file"; +import bytes from "bytes"; + +const PublicDownloadPage = () => { + const [file, setFile] = useState(null); + const params = useParams(); + + const getFile = useCallback(async () => { + try { + const id = params.id!; + const tempToken = params.tempToken!; + const fileResponse = await getPublicFileInfoAPI(id, tempToken); + setFile(fileResponse); + } catch (e) { + console.log("Error getting publicfile info", e); + toast.error("Error getting public file"); + } + }, [params.id, params.tempToken, getPublicFileInfoAPI]); + + const downloadItem = useCallback(() => { + const id = params.id!; + const tempToken = params.tempToken!; + downloadPublicFileAPI(id, tempToken); + }, [params.id, params.tempToken, downloadPublicFileAPI]); + + useEffect(() => { + getFile(); + }, [getFile]); + + if (!file) { + return ( +
+ + +
+ ); + } + + const fileExtension = getFileExtension(file.filename, 3); + + const imageColor = getFileColor(file.filename); + + const formattedDate = moment(file.uploadDate).format("L"); + + const fileSize = bytes(file.metadata.size); + + return ( +
+
+
+
+ +
+ + {fileExtension} + +
+
+

+ {file.filename} +

+
+
+
+
+ + Type + + + {fileExtension} + +
+
+ + Size + + + {fileSize} + +
+
+ + Created + + + {formattedDate} + +
+
+ + Access + + + {file.metadata.link ? "Public" : "Private"} + +
+ +
+
+ +
+ ); +}; + +export default PublicDownloadPage; diff --git a/src/components/Homepage/index.tsx b/src/components/Homepage/index.tsx index c103dbc..5f9eedb 100644 --- a/src/components/Homepage/index.tsx +++ b/src/components/Homepage/index.tsx @@ -9,6 +9,10 @@ import { useAppSelector } from "../../hooks/store"; import { ToastContainer } from "react-toastify"; const Homepage = () => { + const showUploader = useAppSelector( + (state) => state.uploader.uploads.length !== 0 + ); + return (
@@ -17,7 +21,7 @@ const Homepage = () => {
- + {showUploader && }
diff --git a/src/components/PhotoViewerPopup/index.tsx b/src/components/PhotoViewerPopup/index.tsx index a5fdc2d..4f19669 100644 --- a/src/components/PhotoViewerPopup/index.tsx +++ b/src/components/PhotoViewerPopup/index.tsx @@ -298,7 +298,10 @@ const PhotoViewerPopup = memo(() => { className="max-w-[80vw] max-h-[80vh] flex justify-center items-center" > {!file.metadata.isVideo && ( - + )} {file.metadata.isVideo && (