improved uploaded and made axios interceptor typescript

This commit is contained in:
subnub
2024-07-22 09:51:06 -04:00
parent 93d4b24936
commit bac7867c0c
12 changed files with 84 additions and 380 deletions
+7 -10
View File
@@ -1,8 +1,6 @@
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;
@@ -81,11 +79,10 @@ export const downloadFileAPI = async (fileID: string) => {
export const getFileThumbnailAPI = async (thumbnailID: string) => {
// TODO: Change this
const url = `http://localhost:5173/api/file-service/thumbnail/${thumbnailID}`;
const config = {
responseType: "arraybuffer",
};
const response = await axios.get(url, config);
const response = await axios.get(url, {
responseType: "arraybuffer",
});
const imgFile = new Blob([response.data]);
const imgUrl = URL.createObjectURL(imgFile);
@@ -94,11 +91,10 @@ export const getFileThumbnailAPI = async (thumbnailID: string) => {
};
export const getFileFullThumbnailAPI = async (fileID: string) => {
const config = {
responseType: "arraybuffer",
};
const url = `http://localhost:5173/api/file-service/full-thumbnail/${fileID}`;
const response = await axios.get(url, config);
const response = await axios.get(url, {
responseType: "arraybuffer",
});
return response.data;
};
@@ -206,6 +202,7 @@ export const removeLinkAPI = async (fileID: string) => {
};
// DELETE
export const deleteFileAPI = async (fileID: string) => {
const response = await axios.delete(`/file-service/remove`, {
data: {
@@ -6,7 +6,7 @@ let browserIDCheck = localStorage.getItem("browser-id");
const sleep = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
resolve(true);
}, 150);
});
};
@@ -74,7 +74,7 @@ axiosRetry.interceptors.response.use(
// The old request will still be open and it will not make a
// Brand new request sometimes, so it will log users out
// But adding a sleep function seems to fix this.
return sleep("sleepy boi");
return sleep();
})
.then((sleepres) => {
return axios3(originalRequest);
@@ -90,64 +90,4 @@ axiosRetry.interceptors.response.use(
}
);
// axios.interceptors.response.use( (response) => {
// console.log("axios interceptor")
// // Return a successful response back to the calling service
// return response;
// }, (error) => {
// const originalRequest = error.config;
// if (originalRequest.ran) {
// console.log("Request already ran");
// return Promise.reject(error);
// }
// console.log("axios interceptor failed first request")
// // Return any error which is not due to authentication back to the calling service
// if (error.response.status !== 401) {
// console.log("error does not equal 401");
// return new Promise((resolve, reject) => {
// reject(error);
// });
// }
// // Logout user if token refresh didn't work or user is disabled
// console.log("error url", error.config.url);
// if (error.config.url === "/user-service/get-token") {
// console.log("error url equal to refresh token route")
// return new Promise((resolve, reject) => {
// reject(error);
// });
// }
// // Try request again with new token
// // return new Promise((resolve, reject) => {
// // })
// return axios.post("/user-service/get-token").then((cookieResponse) => {
// console.log("cookie status", cookieResponse.status);
// if (cookieResponse.status === 201) {
// console.log("cookie response", cookieResponse.data);
// originalRequest.ran = true;
// return axios(originalRequest);
// } else {
// return Promise.reject(error);
// }
// })
// // .catch((cookieError) => {
// // console.log("cookieError", cookieError);
// // return Promise.reject(error);
// // })
// });
export default axiosRetry;
+25 -33
View File
@@ -3,12 +3,10 @@ import { createFolderAPI } from "../../api/foldersAPI";
import { useFoldersClient } from "../../hooks/folders";
import { useClickOutOfBounds } from "../../hooks/utils";
import { showCreateFolderPopup } from "../../popups/folder";
import { useAppDispatch } from "../../hooks/store";
import { startAddFile } from "../../actions/files";
import { RefObject, useRef } from "react";
import axiosNonInterceptor from "axios";
import uuid from "uuid";
import { useUploader } from "../../hooks/files";
import UploadFileIcon from "../../icons/UploadFileIcon";
import CreateFolderIcon from "../../icons/CreateFolderIcon";
interface AddNewDropdownProps {
closeDropdown: () => void;
@@ -20,7 +18,6 @@ const AddNewDropdown: React.FC<AddNewDropdownProps> = (props) => {
const { wrapperRef } = useClickOutOfBounds(props.closeDropdown);
const uploadRef: RefObject<HTMLInputElement> = useRef(null);
const { uploadFiles } = useUploader();
const dispatch = useAppDispatch();
const createFolder = async () => {
props.closeDropdown();
@@ -37,7 +34,6 @@ const AddNewDropdown: React.FC<AddNewDropdownProps> = (props) => {
const handleUpload = (e: any) => {
e.preventDefault();
props.closeDropdown();
console.log("handle upload");
const files = uploadRef.current?.files;
if (!files) return;
@@ -45,44 +41,40 @@ const AddNewDropdown: React.FC<AddNewDropdownProps> = (props) => {
uploadFiles(files);
};
const triggerFileUpload = () => {
if (uploadRef.current) {
uploadRef.current.click();
}
};
return (
<div ref={wrapperRef} className="absolute bottom-0 top-full w-full">
<ul className="pl-0 list-none m-0 rounded-[5px] overflow-hidden bg-white shadow-[0px_2px_4px_rgba(0,0,0,0.15),_inset_0px_1px_0px_#F5F7FA]">
<input
className="hidden"
ref={uploadRef}
type="file"
multiple={true}
onChange={handleUpload}
/>
<ul className="pl-0 list-none m-0 rounded-[5px] overflow-hidden shadow-md">
<li>
<div>
<input
className="w-full top-0 bg-red-500 h-[41px] mt-[3px] cursor-pointer absolute opacity-0"
// @ts-ignore
ref={uploadRef}
type="file"
multiple={true}
onChange={handleUpload}
/>
<a className="flex items-center bg-white justify-start p-[12px_20px] transition-all duration-400 ease-in-out no-underline rounded-[5px] overflow-hidden text-[#0E1C71] text-[15px] leading-[18px]">
<span className="inline-flex min-w-[30px]">
<img
className="max-w-full h-auto"
src="/assets/uploadicon.svg"
alt="upload"
/>
</span>{" "}
Upload Files
<a
className="flex items-center justify-start p-[12px_20px] no-underline rounded-[5px] overflow-hidden text-[15px] leading-[18px] bg-white hover:bg-[#f6f5fd]"
onClick={triggerFileUpload}
>
<UploadFileIcon className="w-[20px] h-[20px] mr-[10px] text-[#3c85ee]" />
<p className="text-sm">Upload Files</p>
</a>
</div>
</li>
<li>
<a
className="flex items-center bg-white justify-start p-[12px_20px] transition-all duration-400 ease-in-out no-underline rounded-[5px] overflow-hidden text-[#0E1C71] text-[15px] leading-[18px]"
className="flex items-center justify-start p-[12px_20px] no-underline rounded-[5px] overflow-hidden text-[15px] leading-[18px] bg-white hover:bg-[#f6f5fd]"
onClick={createFolder}
>
<span className="inline-flex min-w-[30px]">
<img
className="max-w-full h-auto"
src="/assets/foldericon.svg"
alt="folder"
/>
</span>{" "}
Create Folder
<CreateFolderIcon className="w-[20px] h-[20px] mr-[10px] text-[#3c85ee]" />
<p className="text-sm">Create Folder</p>
</a>
</li>
</ul>
+4 -3
View File
@@ -1,6 +1,6 @@
import QuickAccess from "../QuickAccess";
import Folders from "../Folders";
import { useFiles, useQuickFiles } from "../../hooks/files";
import { useFiles, useQuickFiles, useUploader } from "../../hooks/files";
import { useInfiniteScroll } from "../../hooks/infiniteScroll";
import Files from "../Files";
import { memo, useCallback, useEffect, useRef, useState } from "react";
@@ -28,6 +28,7 @@ const DataForm = memo(() => {
const { sentinelRef, reachedIntersect } = useInfiniteScroll();
const [initialLoad, setInitialLoad] = useState(true);
const params = useParams();
const { uploadFiles } = useUploader();
const isLoading = isLoadingFiles || isLoadingFolders || isLoadingQuickItems;
@@ -44,8 +45,8 @@ const DataForm = memo(() => {
}, [reachedIntersect, initialLoad, isFetchingNextPage]);
const addFile = useCallback(
(file: FileInterface) => {
dispatch(startAddFile(file, params.id));
(files: FileList) => {
uploadFiles(files);
},
[params.id]
);
+2 -2
View File
@@ -13,7 +13,7 @@ import { useAppDispatch, useAppSelector } from "../../hooks/store";
import { closeDrawer } from "../../reducers/leftSection";
import SettingsIcon from "../../icons/SettingsIcon";
const LeftSection = (props) => {
const LeftSection = () => {
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const leftSectionOpen = useAppSelector((state) => state.leftSection.drawOpen);
const { isHome, isTrash, isMedia, isSettings } = useUtils();
@@ -89,7 +89,7 @@ const LeftSection = (props) => {
<div className="relative mb-[30px]">
<a
onClick={openDropdown}
className="flex items-center justify-center bg-[#3c85ee] no-underline rounded-[5px]"
className="flex items-center justify-center bg-[#3c85ee] hover:bg-[#326bcc] no-underline rounded-[5px]"
>
<p className="m-0 w-full text-center text-white text-[16px] font-medium">
ADD NEW
-257
View File
@@ -1,257 +0,0 @@
import LoginPage from "./LoginPage";
import {
startLogin,
startLoginCheck,
startCreateAccount,
} from "../../actions/auth";
import { setLoginFailed, setCreateNewAccount } from "../../actions/main";
import { connect } from "react-redux";
import React from "react";
import axios from "../../axiosInterceptor";
import Swal from "sweetalert2";
import env from "../../enviroment/envFrontEnd";
import withNavigate from "../HocComponent";
class LoginPageContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
value: undefined,
loginMode: true,
email: "",
password: "",
verifyPassword: "",
resetPasswordMode: false,
verifyEmailResent: false,
verifyEmailResentTimer: 0,
verifyEmailResentTimerStarted: false,
};
this.timer;
}
loginWithToken = async () => {
console.log("login with token");
const loginSuccessful = await this.props.dispatch(startLoginCheck());
const loginRedirectRoute =
this.props.location.state?.from?.pathname || "/home";
if (loginSuccessful) {
this.props.navigate(loginRedirectRoute);
}
};
componentDidUpdate = () => {
if (this.props.createNewAccount) {
this.props.dispatch(setCreateNewAccount(false));
Swal.fire({
icon: "info",
title: "Email Verification Sent",
text: "Sent Email Verification, Please Check Your Inbox.",
});
}
};
login = async (e) => {
e.preventDefault();
const email = this.state.email;
const password = this.state.password;
const verifyPassword = this.state.verifyPassword;
if (this.state.resetPasswordMode) {
const data = {
email,
};
axios
.post("/user-service/send-password-reset", data)
.then((response) => {
Swal.fire(
"Check your email",
"If the email address matches any in our database, well send you an email with instructions on how to reset your password.",
"success"
);
})
.catch((err) => {
console.log("Reset Password Err", err);
});
} else if (this.state.loginMode) {
const loginSuccessful = await this.props.dispatch(
startLogin(email, password, this.props.currentRoute)
);
if (loginSuccessful) {
this.props.navigate(this.props.currentRoute);
}
} else if (password === verifyPassword) {
this.props.dispatch(startCreateAccount(email, password));
} else {
this.props.dispatch(setLoginFailed("Passwords Do Not Match"));
}
};
switchResetPasswordMode = () => {
this.setState(() => {
return {
...this.state,
resetPasswordMode: !this.state.resetPasswordMode,
};
});
};
switchLoginMode = () => {
this.setState(() => {
return {
...this.state,
loginMode: !this.state.loginMode,
};
});
};
emailOnChange = (e) => {
const value = e.target.value;
this.setState(() => ({
...this.state,
email: value,
}));
};
passwordOnChange = (e) => {
const value = e.target.value;
this.setState(() => ({
...this.state,
password: value,
}));
};
verifyPasswordOnChange = (e) => {
const value = e.target.value;
this.setState(() => ({
...this.state,
verifyPassword: value,
}));
};
startVerifyEmailTimer = () => {
this.timer = window.setInterval(this.decreaseVerifyTimer, 1000);
};
decreaseVerifyTimer = () => {
if (
this.state.verifyEmailResentTimer <= 0 &&
this.state.verifyEmailResentTimerStarted
) {
clearInterval(this.timer);
return this.setState(() => {
return {
...this.state,
verifyEmailResentTimerStarted: false,
verifyEmailResentTimer: 0,
verifyEmailResent: false,
};
});
}
this.setState(() => {
return {
...this.state,
verifyEmailResentTimer: this.state.verifyEmailResentTimer - 1,
};
});
};
resendEmail = () => {
if (this.state.verifyEmailResentTimer !== 0) {
console.log("verify email timer not at 0 yet");
return;
}
axios.post("/user-service/resend-verify-email").then((response) => {
this.setState(
() => {
return {
...this.state,
verifyEmailResent: true,
verifyEmailResentTimer: 59,
verifyEmailResentTimerStarted: true,
};
},
() => {
this.startVerifyEmailTimer();
}
);
});
};
logout = () => {
// window.localStorage.removeItem("token");
axios
.post("/user-service/logout")
.then((response) => {
console.log("user logged out verify email");
//this.props.dispatch(setLoginFailed(false))
window.location.reload();
// this.setState(() => {
// return {
// ...this.state,
// value: undefined,
// loginMode: true,
// email: "",
// password: "",
// verifyPassword: "",
// resetPasswordMode: false,
// verifyEmailResent: false,
// verifyEmailResentTimer: 0,
// verifyEmailResentTimerStarted: false,
// }
// })
})
.catch((e) => {
window.location.reload();
console.log("Cannot logout user verify email");
});
};
componentDidMount = () => {
env.emailAddress = "";
this.setState(() => ({
...this.state,
email: "",
}));
// this.loginWithToken();
};
render() {
return (
<LoginPage
loginWithToken={this.loginWithToken}
switchLoginMode={this.switchLoginMode}
switchResetPasswordMode={this.switchResetPasswordMode}
login={this.login}
emailOnChange={this.emailOnChange}
passwordOnChange={this.passwordOnChange}
verifyPasswordOnChange={this.verifyPasswordOnChange}
resendEmail={this.resendEmail}
logout={this.logout}
{...this.props}
state={this.state}
/>
);
}
}
const mapStateToProps = (state) => ({
id: state.auth.id,
loginFailed: state.main.loginFailed,
loginFailedCode: state.main.loginFailedCode,
createNewAccount: state.main.createNewAccount,
});
export default connect(mapStateToProps)(withNavigate(LoginPageContainer));
@@ -209,7 +209,7 @@ const LoginPage = () => {
disabled={
isSubmitDisabled || loadingLogin || validationError !== ""
}
className="bg-[#3c85ee] border border-[#3c85ee] rounded-[5px] text-white text-[15px] font-medium cursor-pointer py-2 px-4 disabled:opacity-50 disabled:cursor-not-allowed"
className="bg-[#3c85ee] border border-[#3c85ee] hover:bg-[#326bcc] rounded-[5px] text-white text-[15px] font-medium cursor-pointer py-2 px-4 disabled:opacity-50 disabled:cursor-not-allowed"
/>
</div>
+3 -3
View File
@@ -1,5 +1,5 @@
import { connect } from "react-redux";
import React, { useEffect, useRef } from "react";
import React, { memo, useEffect, useRef } from "react";
import { useFilesClient, useQuickFilesClient } from "../../hooks/files";
import { getCancelToken } from "../../utils/cancelTokenManager";
import CloseIcon from "../../icons/CloseIcon";
@@ -26,7 +26,7 @@ const UploadItem: React.FC<UploadItemType> = (props) => {
cancelToken.cancel();
};
const ProgressIcon = () => {
const ProgressIcon = memo(() => {
if (completed) {
return <CheckCircleIcon className="w-[20px] h-[20px] text-green-600" />;
} else if (canceled) {
@@ -39,7 +39,7 @@ const UploadItem: React.FC<UploadItemType> = (props) => {
/>
);
}
};
});
return (
<div className="relative p-[20px] flex justify-between items-start hover:bg-[#f6f5fd]">
+1 -3
View File
@@ -78,9 +78,7 @@ export const useDragAndDrop = (fileDroppedCallback: (file: any) => any) => {
isDraggingFileRef.current = false;
setIsDraggingFile(false);
const fileInput = e.dataTransfer;
fileDroppedCallback(fileInput);
fileDroppedCallback(e.dataTransfer.files);
},
[fileDroppedCallback]
);
+22
View File
@@ -0,0 +1,22 @@
type CreateFolderIconType = React.SVGAttributes<SVGSVGElement>;
const CreateFolderIcon: React.FC<CreateFolderIconType> = (props) => {
return (
<svg
viewBox="0 0 19 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<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.5ZM8 7.999V6H6V7.999L4 8V10L6 9.999V12H8V9.999L10 10V8L8 7.999Z"
fill="currentColor"
/>
</svg>
);
};
export default CreateFolderIcon;
+17
View File
@@ -0,0 +1,17 @@
type UploadFileIconType = React.SVGAttributes<SVGSVGElement>;
const UploadFileIcon: React.FC<UploadFileIconType> = (props) => {
return (
<svg viewBox="0 0 15 18" xmlns="http://www.w3.org/2000/svg" {...props}>
<path
id="Combined Shape"
fill-rule="evenodd"
clip-rule="evenodd"
d="M4 1.7693e-05V0H2V1.7693e-05H1.68094C0.75257 1.7693e-05 0 0.752587 0 1.68096V2V4V16.2491C0 17.1774 0.75257 17.93 1.68094 17.93H12.8872C13.8156 17.93 14.5681 17.1774 14.5681 16.2491V3.92221C14.569 3.77327 14.5105 3.63014 14.4056 3.52438L11.0438 0.162508C10.938 0.0576248 10.7949 -0.000822776 10.6459 1.7693e-05H4ZM2 1.12064H1.68094C1.37147 1.12064 1.12063 1.37149 1.12063 1.68096V2H2V1.12064ZM4 2V1.12064H10.0856V3.36189C10.0856 3.98079 10.5873 4.48252 11.2062 4.48252H13.4475V16.2491C13.4475 16.5585 13.1967 16.8094 12.8872 16.8094H1.68094C1.37147 16.8094 1.12063 16.5585 1.12063 16.2491V4H2V6H4V4H6V2H4Z"
fill="currentColor"
/>
</svg>
);
};
export default UploadFileIcon;
-6
View File
@@ -1,5 +1,3 @@
import axios from "../axiosInterceptor";
interface MapType {
[key: string]: {
token: any;
@@ -28,7 +26,3 @@ export const cancelAllFileUploads = () => {
delete cancelTokens[key];
}
};
// export const cancelFileUpload = (fileId) => {
// };