diff options
Diffstat (limited to 'src/views/Authorization/LoginView.jsx')
-rw-r--r-- | src/views/Authorization/LoginView.jsx | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/src/views/Authorization/LoginView.jsx b/src/views/Authorization/LoginView.jsx new file mode 100644 index 0000000..2ffcef4 --- /dev/null +++ b/src/views/Authorization/LoginView.jsx @@ -0,0 +1,345 @@ +import GoogleIcon from '@mui/icons-material/Google' +import { + Avatar, + Box, + Button, + Container, + Divider, + Input, + Sheet, + Snackbar, + Typography, +} from '@mui/joy' +import Cookies from 'js-cookie' +import React from 'react' +import { useNavigate } from 'react-router-dom' +import { LoginSocialGoogle } from 'reactjs-social-login' +import { API_URL, GOOGLE_CLIENT_ID, REDIRECT_URL } from '../../Config' +import { UserContext } from '../../contexts/UserContext' +import Logo from '../../Logo' +import { GetUserProfile } from '../../utils/Fetcher' +const LoginView = () => { + const { userProfile, setUserProfile } = React.useContext(UserContext) + const [username, setUsername] = React.useState('') + const [password, setPassword] = React.useState('') + const [error, setError] = React.useState(null) + const Navigate = useNavigate() + const handleSubmit = async e => { + e.preventDefault() + + fetch(`${API_URL}/auth/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ username, password }), + }) + .then(response => { + if (response.status === 200) { + return response.json().then(data => { + localStorage.setItem('ca_token', data.token) + localStorage.setItem('ca_expiration', data.expire) + const redirectUrl = Cookies.get('ca_redirect') + // console.log('redirectUrl', redirectUrl) + if (redirectUrl) { + Cookies.remove('ca_redirect') + Navigate(redirectUrl) + } else { + Navigate('/my/chores') + } + }) + } else if (response.status === 401) { + setError('Wrong username or password') + } else { + setError('An error occurred, please try again') + console.log('Login failed') + } + }) + .catch(err => { + setError('Unable to communicate with server, please try again') + console.log('Login failed', err) + }) + } + + const loggedWithProvider = function (provider, data) { + console.log(provider, data) + return fetch(API_URL + `/auth/${provider}/callback`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + provider: provider, + token: + data['access_token'] || // data["access_token"] is for Google + data['accessToken'], // data["accessToken"] is for Facebook + data: data, + }), + }).then(response => { + if (response.status === 200) { + return response.json().then(data => { + localStorage.setItem('ca_token', data.token) + localStorage.setItem('ca_expiration', data.expire) + // setIsLoggedIn(true); + getUserProfileAndNavigateToHome() + }) + } + return response.json().then(error => { + setError("Couldn't log in with Google, please try again") + }) + }) + } + const getUserProfileAndNavigateToHome = () => { + GetUserProfile().then(data => { + data.json().then(data => { + setUserProfile(data.res) + // check if redirect url is set in cookie: + const redirectUrl = Cookies.get('ca_redirect') + if (redirectUrl) { + Cookies.remove('ca_redirect') + Navigate(redirectUrl) + } else { + Navigate('/my/chores') + } + }) + }) + } + const handleForgotPassword = () => { + Navigate('/forgot-password') + } + return ( + <Container + component='main' + maxWidth='xs' + + // make content center in the middle of the page: + > + <Box + sx={{ + marginTop: 4, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + }} + > + <Sheet + component='form' + sx={{ + mt: 1, + width: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + padding: 2, + borderRadius: '8px', + boxShadow: 'md', + }} + > + {/* <img + src='/src/assets/logo.svg' + alt='logo' + width='128px' + height='128px' + /> */} + <Logo /> + + <Typography level='h2'> + Done + <span + style={{ + color: '#06b6d4', + }} + > + tick + </span> + </Typography> + + {userProfile && ( + <> + <Avatar + src={userProfile?.image} + alt={userProfile?.username} + size='lg' + sx={{ + mt: 2, + width: '96px', + height: '96px', + mb: 1, + }} + /> + <Typography level='body-md' alignSelf={'center'}> + Welcome back,{' '} + {userProfile?.displayName || userProfile?.username} + </Typography> + + <Button + fullWidth + size='lg' + sx={{ mt: 3, mb: 2 }} + onClick={() => { + getUserProfileAndNavigateToHome() + }} + > + Continue as {userProfile.displayName || userProfile.username} + </Button> + <Button + type='submit' + fullWidth + size='lg' + q + variant='plain' + sx={{ + width: '100%', + mb: 2, + border: 'moccasin', + borderRadius: '8px', + }} + onClick={() => { + setUserProfile(null) + localStorage.removeItem('ca_token') + localStorage.removeItem('ca_expiration') + // go to login page: + window.location.href = '/login' + }} + > + Logout + </Button> + </> + )} + {!userProfile && ( + <> + <Typography level='body2'> + Sign in to your account to continue + </Typography> + <Typography level='body2' alignSelf={'start'} mt={4}> + Username + </Typography> + <Input + margin='normal' + required + fullWidth + id='email' + label='Email Address' + name='email' + autoComplete='email' + autoFocus + value={username} + onChange={e => { + setUsername(e.target.value) + }} + /> + <Typography level='body2' alignSelf={'start'}> + Password: + </Typography> + <Input + margin='normal' + required + fullWidth + name='password' + label='Password' + type='password' + id='password' + value={password} + onChange={e => { + setPassword(e.target.value) + }} + /> + + <Button + type='submit' + fullWidth + size='lg' + variant='solid' + sx={{ + width: '100%', + mt: 3, + mb: 2, + border: 'moccasin', + borderRadius: '8px', + }} + onClick={handleSubmit} + > + Sign In + </Button> + <Button + type='submit' + fullWidth + size='lg' + q + variant='plain' + sx={{ + width: '100%', + mb: 2, + border: 'moccasin', + borderRadius: '8px', + }} + onClick={handleForgotPassword} + > + Forgot password? + </Button> + </> + )} + <Divider> or </Divider> + + <Box sx={{ width: '100%' }}> + <LoginSocialGoogle + client_id={GOOGLE_CLIENT_ID} + redirect_uri={REDIRECT_URL} + scope='openid profile email' + discoveryDocs='claims_supported' + access_type='online' + isOnlyGetToken={true} + onResolve={({ provider, data }) => { + loggedWithProvider(provider, data) + }} + onReject={err => { + setError("Couldn't log in with Google, please try again") + }} + > + <Button + variant='soft' + color='neutral' + size='lg' + fullWidth + sx={{ + width: '100%', + mt: 1, + mb: 1, + border: 'moccasin', + borderRadius: '8px', + }} + > + <div className='flex gap-2'> + <GoogleIcon /> + Continue with Google + </div> + </Button> + </LoginSocialGoogle> + </Box> + + <Button + onClick={() => { + Navigate('/signup') + }} + fullWidth + variant='soft' + size='lg' + // sx={{ mt: 3, mb: 2 }} + > + Create new account + </Button> + </Sheet> + </Box> + <Snackbar + open={error !== null} + onClose={() => setError(null)} + autoHideDuration={3000} + message={error} + > + {error} + </Snackbar> + </Container> + ) +} + +export default LoginView |