-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
780cedf
commit e52add1
Showing
3 changed files
with
236 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import Input from '../../../../components/Input'; | ||
|
||
interface AccountInfoProps { | ||
id: number; | ||
email: string; | ||
} | ||
|
||
const AccountInfo: React.FC<AccountInfoProps> = ({ id, email }) => { | ||
return ( | ||
<section | ||
id="account-info" | ||
className="flex flex-col mt-4 mb-12 space-y-6 sm:space-x-20 sm:flex-row sm:space-y-0 sm:mb-4" | ||
> | ||
<Input | ||
type="number" | ||
id="user-local-id" | ||
name="user-local-id" | ||
value={id.toString()} | ||
disabled | ||
placeholder="Internal User ID" | ||
/> | ||
|
||
<Input | ||
type="email" | ||
id="user-email" | ||
name="user-email" | ||
value={email} | ||
disabled | ||
placeholder="Email Address" | ||
/> | ||
</section> | ||
); | ||
}; | ||
|
||
export default AccountInfo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import classNames from 'classnames'; | ||
import React, { useEffect, useState } from 'react'; | ||
import { LazyLoadImage } from 'react-lazy-load-image-component'; | ||
import LoadingIcon from '../../../../assets/icons/loading.svg'; | ||
import UserNoPicture from '../../../../assets/imgs/user.webp'; | ||
import Button from '../../../../components/Button'; | ||
import DropZone from '../../../../components/DropZone'; | ||
import Reveal from '../../../../components/Reveal'; | ||
import { Base64Img } from '../../../../types/types'; | ||
|
||
interface UserPictureProps { | ||
userImage: string; | ||
} | ||
|
||
//TODO: API call to update user image | ||
const UserPicture: React.FC<UserPictureProps> = ({ userImage }) => { | ||
const [updatedImage, setUpdatedImage] = useState<Base64Img[]>([]); | ||
const [isLoading, setIsLoading] = useState<boolean>(false); | ||
|
||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
setIsLoading(true); | ||
}; | ||
|
||
useEffect(() => { | ||
// Every time an image is added to the array, only keep the last one | ||
if (updatedImage.length > 1) { | ||
setUpdatedImage([updatedImage[updatedImage.length - 1]]); | ||
} | ||
}, [updatedImage]); | ||
|
||
return ( | ||
<section id="update-user-picture"> | ||
<form | ||
className="flex flex-col w-full md:space-x-20 md:flex-row" | ||
onSubmit={handleSubmit} | ||
> | ||
<div className="flex flex-col items-center mb-8 md:w-1/2 md:mb-0"> | ||
<Reveal width="100%" animation="slide-right" delay={0.05}> | ||
<h2 className="w-full mb-4 text-2xl font-bellefair text-start"> | ||
Update your profile picture | ||
</h2> | ||
</Reveal> | ||
<Reveal width="100%" animation="slide-left" delay={0.05}> | ||
<div className="flex justify-center"> | ||
<LazyLoadImage | ||
className="my-4 rounded-full w-60 h-60" | ||
src={updatedImage.length > 0 ? updatedImage[0] : userImage} | ||
placeholderSrc={UserNoPicture} | ||
effect="blur" | ||
alt="User Profile Picture" | ||
/> | ||
</div> | ||
</Reveal> | ||
|
||
<Reveal width="100%" animation="slide-bottom"> | ||
<div className="flex flex-row justify-center mt-6 space-x-10"> | ||
<Button | ||
type="submit" | ||
id="update-user-picture-button" | ||
className={classNames( | ||
'text-white bg-zinc-800 py-1.5 disabled:cursor-not-allowed flex justify-center', | ||
isLoading ? 'w-36' : 'w-32', | ||
)} | ||
icon={isLoading ? LoadingIcon : ''} | ||
iconAlt="Loading Icon" | ||
iconAnimation="spin" | ||
disabled={updatedImage.length === 0} | ||
> | ||
Update Image | ||
</Button> | ||
|
||
<Button | ||
type="reset" | ||
id="reset-user-picture-button" | ||
className={classNames( | ||
'text-black bg-white border border-zinc-800 py-1.5 w-32 flex justify-center disabled:cursor-not-allowed', | ||
isLoading ? 'w-36' : 'w-32', | ||
)} | ||
disabled={updatedImage.length === 0} | ||
onClick={() => setUpdatedImage([])} | ||
> | ||
Reset | ||
</Button> | ||
</div> | ||
</Reveal> | ||
</div> | ||
|
||
<div className="flex items-center justify-center md:w-1/2"> | ||
<Reveal width="100%" animation="slide-right" delay={0.05}> | ||
<DropZone | ||
images={updatedImage} | ||
setImages={setUpdatedImage} | ||
maxAllowedImages={1} | ||
/> | ||
</Reveal> | ||
</div> | ||
</form> | ||
</section> | ||
); | ||
}; | ||
|
||
export default UserPicture; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { useEffect, useState } from 'react'; | ||
import requests from '../../api/requests'; | ||
import UserNoPicture from '../../assets/imgs/user.webp'; | ||
import ErrorOccurred from '../../components/ErrorOccurred'; | ||
import Loading from '../../components/Loading'; | ||
import Reveal from '../../components/Reveal'; | ||
import { IUser } from '../../types/types'; | ||
import AccountInfo from './components/AccountInfo'; | ||
import UserPicture from './components/UserPicture'; | ||
|
||
type ExcludedUserProperties = | ||
| 'followers' | ||
| 'following' | ||
| 'isLoggedUser' | ||
| 'isFollowing' | ||
| 'createdAt'; | ||
|
||
export interface User extends Omit<IUser, ExcludedUserProperties> {} | ||
|
||
const ProfileEdit: React.FC = () => { | ||
const [isLoading, setIsLoading] = useState<boolean>(false); | ||
const [errorOccurred, setErrorOccurred] = useState<boolean>(false); | ||
const [user, setUser] = useState<User>({} as User); | ||
|
||
useEffect(() => { | ||
setIsLoading(true); | ||
|
||
const fetchUserData = async (): Promise<void> => { | ||
try { | ||
const response = await requests.users.getLoggedUser(); | ||
|
||
if (response.data.success && response.data.data) { | ||
setUser({ | ||
id: response.data.data.id, | ||
username: response.data.data.username, | ||
email: response.data.data.email, | ||
userImage: response.data.data.userImage, | ||
description: response.data.data.description ?? '', | ||
blocked: response.data.data.blocked, | ||
isAdmin: response.data.data.isAdmin, | ||
resetPasswordToken: response.data.data.resetPasswordToken, | ||
}); | ||
} else { | ||
throw new Error(response.data.message); | ||
} | ||
} catch (error) { | ||
console.log("An error occurred while trying to fetch the user's data: ", error); | ||
setErrorOccurred(true); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
}; | ||
|
||
fetchUserData(); | ||
}, []); | ||
|
||
return ( | ||
<div className="flex flex-col items-center justify-center max-w-3xl mx-auto"> | ||
<Reveal width="100%" animation="slide-right" delay={0.05}> | ||
<h1 className="w-full my-3 text-3xl font-bellefair">Edit Profile</h1> | ||
</Reveal> | ||
|
||
{isLoading && ( | ||
<div className="h-[50vh] flex justify-center items-center"> | ||
<Reveal width="100%" animation="slide-bottom" delay={0.1}> | ||
<Loading /> | ||
</Reveal> | ||
</div> | ||
)} | ||
|
||
{!isLoading && errorOccurred && ( | ||
<div className="h-[50vh] flex justify-center items-center"> | ||
<ErrorOccurred text="An error occurred while trying to fetch the user data." /> | ||
</div> | ||
)} | ||
|
||
{!isLoading && !errorOccurred && Object.keys(user).length > 0 && ( | ||
<div className="w-full my-6"> | ||
<Reveal width="100%" animation="slide-bottom" delay={0.05}> | ||
<AccountInfo id={user.id} email={user.email ?? ''} /> | ||
</Reveal> | ||
|
||
<Reveal width="100%" animation="fade" delay={0.3}> | ||
<hr className="h-px mb-10 bg-gray-200 border-0" /> | ||
</Reveal> | ||
|
||
<UserPicture userImage={user.userImage?.cloudinaryImage ?? UserNoPicture} /> | ||
|
||
<Reveal width="100%" animation="fade" delay={0.3}> | ||
<hr className="h-px my-12 mb-10 bg-gray-200 border-0" /> | ||
</Reveal> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default ProfileEdit; |