Skip to content

Commit

Permalink
uploadProgress
Browse files Browse the repository at this point in the history
  • Loading branch information
A2Fyise committed Feb 2, 2024
1 parent 0a046dd commit 6ae5379
Show file tree
Hide file tree
Showing 17 changed files with 201 additions and 162 deletions.
88 changes: 48 additions & 40 deletions client/app/auth/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const AuthPage: React.FC = () => {
const [name, setName] = useState('');
const [password, setPassword] = useState('');
const [isRegisterMode, setRegisterMode] = useState(false);
const [errorMsg, setErrorMsg] = useState("")

const handleRegisterLinkClick = () => {
setRegisterMode(true);
Expand All @@ -26,6 +27,7 @@ const AuthPage: React.FC = () => {

const handleLogin = async (event: React.MouseEvent<HTMLFormElement>) => {
event.preventDefault();
event.stopPropagation();
try {
const response = await Api.post("/login_user", {
email,
Expand All @@ -40,18 +42,24 @@ const AuthPage: React.FC = () => {
Cookies.set('userName', userName)
dispatch(setProfileImgSrc(profilePicture))

console.log(response.data)

if (response.status === 200) {
router.push(`/view/0`);
} else {
return setErrorMsg("User or Password Invalid")
}

return;
} catch (error) {
console.error(error)
const errorResponse = error.response
if (!errorResponse) return setErrorMsg("User or Password Invalid")
setErrorMsg(errorResponse?.data.error)
}
}

const handleRegister = async (event: React.MouseEvent<HTMLFormElement>) => {
event.preventDefault();
event.stopPropagation();
try {
const response = await Api.post("create_user", {
email,
Expand All @@ -61,58 +69,58 @@ const AuthPage: React.FC = () => {
if (response.status === 200) {
setRegisterMode(false)
}
return;
} catch (error) {
console.error(error)
console.error(error?.response)
router.push('/auth')
}
}

return (
<div className={styles.authContainer}>
<div className={`${styles.authBox} ${styles.noBoxShadow}`}>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
{errorMsg !== "" && <span style={{ color: 'red', fontSize: 14, fontWeight: 500, textTransform: 'capitalize', textAlign: 'center' }}>{errorMsg}</span>}
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 10, justifyContent: 'center' }}>
<img style={{ width: 40, height: 40 }} src="https://ssl.gstatic.com/images/branding/product/1x/drive_2020q4_48dp.png" />
<h2 style={{ marginBlock: 20, fontWeight: 400, textAlign: 'center', fontSize: 26, color: "#333" }}>{isRegisterMode ? "Register" : "Sign In"}</h2>
</div>
<h2 style={{ marginBlock: 20, fontWeight: 400, textAlign: 'center', fontSize: 18, color: "#333" }}>to continue Storage Cloud</h2>
<form onSubmit={isRegisterMode ? handleRegister : handleLogin}>
<div className={styles.inputContainer}>
<input
type="text"
className={styles.input}
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
{isRegisterMode && <div className={styles.inputContainer}>
<input
type="text"
className={styles.input}
placeholder="Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>}
<div className={styles.inputContainer}>
<input
type="password"
className={styles.input}
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div className={styles.buttonContainer}>
<button type="submit" className={styles.button}>{isRegisterMode ? 'Register' : 'Login'}</button>
<p className={styles.registerLink}>
{isRegisterMode
? <>Already registered? <a role="button" onClick={handleBackToLogin}>Login</a></>
: <>Not registered? <a role='button' onClick={handleRegisterLinkClick}>Register</a></>}
</p>
<div className={styles.inputContainer}>
<input
type="text"
className={styles.input}
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
{isRegisterMode && <div className={styles.inputContainer}>
<input
type="text"
className={styles.input}
placeholder="Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>}
<div className={styles.inputContainer}>
<input
type="password"
className={styles.input}
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div className={styles.buttonContainer}>
<button onClick={isRegisterMode ? handleRegister : handleLogin} type="submit" className={styles.button}>{isRegisterMode ? 'Register' : 'Login'}</button>
<div className={styles.registerLink}>
{isRegisterMode
? <>Already registered? <a role="button" onClick={handleBackToLogin}>Login</a></>
: <>Not registered? <a role='button' onClick={handleRegisterLinkClick}>Register</a></>}
</div>
</form>
</div>
</div>
</div>
);
Expand Down
8 changes: 7 additions & 1 deletion client/app/components/List/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useRef } from 'react'
import { ListProp } from './List.type'
import styles from './List.module.css'
import { useAppDispatch, useAppSelector } from '@/app/store/hooks';
import { setIsContextMenu, setIsModal, setIsTookAction } from '@/app/store/slice';
import { setIsContextMenu, setIsModal, setIsTookAction, setIsUploading, setUploadFileName, setUploadProgressVisible } from '@/app/store/slice';
import Api from "AxiosInterceptor";
import Cookies from 'js-cookie';
import { useParams } from 'next/navigation';
Expand All @@ -16,7 +16,11 @@ const List: React.FC<ListProp> = ({ children, isVisible }) => {
const onFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
try {
const selectedFile = event.target.files?.[0];
console.log(selectedFile)
if (!selectedFile) return
dispatch(setUploadProgressVisible(true));
dispatch(setUploadFileName(selectedFile.name));
dispatch(setIsUploading(true));
const formData = new FormData();
formData.append('file', selectedFile);

Expand All @@ -39,6 +43,8 @@ const List: React.FC<ListProp> = ({ children, isVisible }) => {
directoryId: +params?.id
})
if (res.status === 200) {
dispatch(setUploadFileName("File"));
dispatch(setIsUploading(false));
dispatch(setIsTookAction(!isTookAction));
}
} catch (error) {
Expand Down
15 changes: 5 additions & 10 deletions client/app/components/UploadProgress/UploadProgress.module.css
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
.container {
transform: translate3d(0, 24px, 0);
transition: transform .15s cubic-bezier(0.4, 0.0, 1, 1), opacity .15s cubic-bezier(0.4, 0.0, 1, 1), visibility 0ms linear .15s;
bottom: 0;
border-radius: 1rem 1rem 0 0;

box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12), 0 1px 3px 1px rgba(60, 64, 67, 0.15);
display: block;
left: auto;
max-height: 323px;
overflow: visible;
border-radius: 15px 15px 0 0;
overflow: hidden;
position: absolute;
right: 24px;
visibility: hidden;
z-index: 1001;
bottom: 0;
right: 30px;
width: 360px;
}
39 changes: 37 additions & 2 deletions client/app/components/UploadProgress/UploadProgress.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,45 @@
import React from 'react'
import styles from './UploadProgress.module.css'
import MaterialSymbolIcon from '../MaterialSymbolIcon/MaterialSymbolIcon'
import { useAppDispatch, useAppSelector } from '@/app/store/hooks'
import { setUploadProgressVisible } from '@/app/store/slice'

const UploadProgress = () => {
return (
const dispatch = useAppDispatch();
const { uploadFileName, uploadProgressVisible, isUploading } = useAppSelector(state => state.slice);

const onClose = () => {
dispatch(setUploadProgressVisible(false))
}

if (!uploadProgressVisible) {
return <></>
} else return (
<div className={styles.container}>
<h1 style={{ color: "#000" }}>hahhaa</h1>
<div style={{ display: 'flex', padding: 10, backgroundColor: "#f8fafd", height: 60, alignItems: 'center', justifyContent: 'space-between' }}>
<div>
<label style={{ fontSize: 16, fontWeight: 500 }}>Uploading file</label>
</div>
<div style={{ display: 'flex' }}>
<MaterialSymbolIcon enableHover title='expand_more' size={26} />
<div onClick={onClose}>
<MaterialSymbolIcon enableHover title='close' size={24} />
</div>
</div>
</div>
<div style={{ display: 'flex', padding: "8px 15px", gap: 15, alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', gap: 10 }}>
<img className="a-Ua-c" src="//ssl.gstatic.com/docs/doclist/images/mediatype/icon_1_image_x16.png" alt="Image" />
<span>{uploadFileName.slice(0, 10)} Name</span>
</div>
<>
{isUploading ?
<MaterialSymbolIcon title='download' />
:
<svg style={{ marginRight: 10 }} className="a-s-fa-Ha-pa c-qd" width="24px" height="24px" viewBox="0 0 24 24" fill="#0F9D58"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"></path></svg>
}
</>
</div>
</div>
)
}
Expand Down
2 changes: 1 addition & 1 deletion client/app/components/UserMenu/UserMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import styles from './UserMenu.module.css'
import { useAppDispatch, useAppSelector } from '@/app/store/hooks';
import useClickOutside from '@/app/hooks/useClickOutside';
import { setProfileImgSrc, toggleUserMenu } from '@/app/store/slice';
import Api from '@/app/service/Api.interceptor';
import Api from 'AxiosInterceptor';

const UserMenu: React.FC = () => {
const router = useRouter();
Expand Down
50 changes: 13 additions & 37 deletions client/app/service/Api.interceptor.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
import axios from 'axios';
import Cookies from 'js-cookie';

const baseURL = process.env.BASE_URL || "https://storage-cloud-server.onrender.com";

const baseURL = "http://localhost:5000"
const Api = axios.create({ baseURL });

export const signOut = () => {
['refreshToken', 'accessToken', 'userId', 'userName'].forEach((cookie) => {
Cookies.remove(cookie)
})
window.location.href = '/auth';
}

const errorMessage = 'API call failed';
const MAX_REFRESH_ATTEMPTS = 3;

let refreshAttempts = 0;

const requiresAuthentication = (url: string) => {
const authenticatedRoutes = ['/get_folder_path', '/get_file'];

Expand All @@ -30,16 +17,12 @@ Api.interceptors.request.use((config) => {
if (requiresAuthentication(configURL)) {
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`;
} else {
console.log('No bearer token found. Logging out.');
signOut();
}
}

return config;
}, (error) => {
console.log(errorMessage, error);
signOut();
console.log(error);
return Promise.reject(error);
});

Expand All @@ -48,26 +31,19 @@ Api.interceptors.response.use((response) => response,
async (error) => {
console.log(error.response.status);
if (error.response.status === 401) {
if (refreshAttempts < MAX_REFRESH_ATTEMPTS) {
try {
const token = Cookies.get('refreshToken');
const response = await Api.post(`/refresh-token`, { token });
const newAccessToken = response.data.accessToken;
Cookies.set('accessToken', newAccessToken);
refreshAttempts += 1;
return Api(error.config);
} catch (error) {
console.log('Failed to refresh access token', error);
return Promise.reject('Failed to refresh access token');
}
} else {
console.log('Max refresh attempts reached. Logging out.');
signOut();
try {
const token = Cookies.get('refreshToken');
const response = await Api.post(`/refresh-token`, { token });
const newAccessToken = response.data.accessToken;
Cookies.set('accessToken', newAccessToken);
return Api(error.config);
} catch (error) {
console.log('Failed to refresh access token', error);
return Promise.reject('Failed to refresh access token');
}
} else {
console.log(errorMessage, error);
signOut();
return Promise.reject(errorMessage);
console.log(error);
return Promise.reject(error);
}
});
export default Api;
Expand Down
17 changes: 16 additions & 1 deletion client/app/store/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export const Slice = createSlice({
currentBreadcrumbFolder: null,
userMenuVisible: false,
profileImgSrc: null,
uploadFileName: "File",
uploadProgressVisible: false,
isUploading: false,
breadCrumbList: [""]
},
reducers: {
Expand Down Expand Up @@ -54,6 +57,15 @@ export const Slice = createSlice({
setProfileImgSrc: (state, action) => {
state.profileImgSrc = action.payload
},
setUploadFileName: (state, action) => {
state.uploadFileName = action.payload
},
setUploadProgressVisible: (state, action) => {
state.uploadProgressVisible = action.payload
},
setIsUploading: (state, action) => {
state.isUploading = action.payload
},
setBreadCrumbList: (state, action) => {
if (action.payload === null) return
state.breadCrumbList = Array.from(new Set([...state.breadCrumbList, action.payload]));
Expand All @@ -74,6 +86,9 @@ export const {
setModalType,
setModalInputValue,
toggleUserMenu,
setProfileImgSrc
setProfileImgSrc,
setUploadFileName,
setUploadProgressVisible,
setIsUploading
} = Slice.actions

Loading

0 comments on commit 6ae5379

Please sign in to comment.