Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avatar image component #140

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
87 changes: 87 additions & 0 deletions client/src/Pages/Profile/UserInfo/UserAvatar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { useState } from 'react';
import Axios from 'axios';
import { Typography } from '@material-ui/core';
import { Alert } from '@material-ui/lab';

import Button from '../../../../Components/Button';
import useStyles from './style';

export default function index() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of index you should give this the component name UserAvatar - it'll help with debugging

const classes = useStyles();
const [previewSource, setPreviewSource] = useState();
// eslint-disable-next-line no-unused-vars
const [inputFileState, setInputFileState] = useState('');
const [selectedFile, setSelectedFile] = useState();
const [errorMsg, setErrorMsg] = useState('');

const previewFile = (file) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome

const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
setPreviewSource(reader.result);
};
};

const handleUploadFile = (e) => {
const file = e.target.files[0];
previewFile(file);
setSelectedFile(file);
};

const uploadImage = async (base64EncodedImage) => {
try {
await Axios.post('/api/v1/upload', base64EncodedImage);
setInputFileState('');
setPreviewSource('');
setErrorMsg('Image uploaded successfully');
} catch (err) {
setErrorMsg('Something went wrong!');
}
};

const handleSubmitImage = (e) => {
e.preventDefault();
if (!selectedFile) return;
const reader = new FileReader();
reader.readAsDataURL(selectedFile);
reader.onloadend = () => {
uploadImage(reader.result);
};
reader.onerror = () => {
setErrorMsg('Something went wrong!');
};
};

return (
<div className={classes.modal}>
<Typography variant="h6">Choose an image</Typography>
{errorMsg && <Alert variant="error">{errorMsg}</Alert>}
<div className={classes.formContainer}>
<form className={classes.avtarForm} onSubmit={handleSubmitImage}>
<label htmlFor="file-input-select">
Chose file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose

<input
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest that you add the accepts attribute to the file input to make sure the user can only upload images

type="file"
name="image"
id="file-input-select"
value={inputFileState}
onChange={handleUploadFile}
className={classes.selectFileBtn}
/>
</label>
<Button
type="submit"
variant="contained"
color="secondary"
className={classes.uploadBtn}
>
Upload
</Button>
</form>
<div className={classes.imagePreview}>
{previewSource && <img src={previewSource} alt="avatar" />}
</div>
</div>
</div>
);
}
71 changes: 71 additions & 0 deletions client/src/Pages/Profile/UserInfo/UserAvatar/style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles((theme) => ({
modal: {
position: 'absolute',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
width: 400,
backgroundColor: '#F5F5F5',
border: '1px solid #c7c7c7',
borderRadius: '4px',
padding: theme.spacing(2, 4, 3),
left: 'calc(50% - 200px)',
top: 'calc(50% - 200px)',
'& h6': {
color: theme.palette.primary.dark,
fontWeight: 'bold',
},
},
formContainer: {
marginTop: '1rem',
width: '100%',
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
},
avtarForm: {
width: '40%',
'& label': {
display: 'inline-block',
width: '85px',
height: '35px',
color: theme.palette.primary.dark,
backgroundColor: '#F5F5F5',
border: `1px solid ${theme.palette.primary.dark}`,
borderRadius: '3px',
padding: '0.5em',
textAlign: 'center',
cursor: 'pointer',
transition: 'all 0.25s',
'&:hover': {
color: '#F5F5F5',
backgroundColor: theme.palette.primary.dark,
border: '1px solid #F5F5F5',
transition: 'all 0.25s',
},
},
},
selectFileBtn: {
visibility: 'hidden',
},
imagePreview: {
width: '60%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '100px',
backgroundColor: '#c7c7c7',
borderRadius: '5px',
'& img': {
width: '150px',
},
},
uploadBtn: {
color: '#f5f5f5',
marginTop: '1em',
},
}));

export default useStyles;
34 changes: 30 additions & 4 deletions client/src/Pages/Profile/UserInfo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import {
Grid,
Paper,
CircularProgress,
Modal,
} from '@material-ui/core';
import { Alert } from '@material-ui/lab';
import PermMediaIcon from '@material-ui/icons/PermMedia';

import Button from '../../../Components/Button';
import UserAvatar from './UserAvatar';

import useStyles from './style';

Expand All @@ -19,6 +22,7 @@ function UserInfo({ getUserName }) {
const [user, setUser] = useState({});
const [loading, setLoading] = useState(false);
const [errorMsg, setErrorMsg] = useState('');
const [open, setOpen] = useState(false);

useEffect(() => {
let isCurrent = true;
Expand All @@ -42,17 +46,39 @@ function UserInfo({ getUserName }) {
};
}, []);

const handleOpen = () => {
setOpen(true);
};

const handleClose = () => {
setOpen(false);
};

return (
<div className={classes.root}>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="simple-modal-title"
aria-describedby="simple-modal-description"
>
<UserAvatar />
</Modal>
<Typography variant="h2">User Information</Typography>
{loading ? (
<CircularProgress />
) : (
<>
<Grid lg="12" justify="center">
<Avatar className={classes.avatar}>
{user.username && user.username.slice(0, 1).toUpperCase()}
</Avatar>
<Grid lg="false" justify="center">
<div className={classes.avatarBox}>
<Avatar className={classes.avatar}>
{user.username && user.username.slice(0, 1).toUpperCase()}
</Avatar>
<PermMediaIcon
className={classes.avatarBtn}
onClick={handleOpen}
/>
</div>
</Grid>
<Grid justify="center">
{errorMsg ? (
Expand Down
14 changes: 14 additions & 0 deletions client/src/Pages/Profile/UserInfo/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ const useStyles = makeStyles((theme) => ({
color: theme.palette.primary.main,
},
},
avatarBox: {
margin: '0 auto',
width: '150px',
textAlign: 'right',
},
avatarBtn: {
color: '#757575',
cursor: 'pointer',
transition: 'all 0.25s',
'&:hover': {
color: theme.palette.primary.dark,
transition: 'all 0.25s',
},
},
avatar: {
width: '5em',
height: '5em',
Expand Down