aboutsummaryrefslogtreecommitdiffstats
path: root/src/views/Authorization/LoginView.jsx
diff options
context:
space:
mode:
authorLibravatar Mo Tarbin <mhed.t91@gmail.com>2024-06-30 18:55:39 -0400
committerLibravatar Mo Tarbin <mhed.t91@gmail.com>2024-06-30 18:55:39 -0400
commit2657469964e24ffbeb905024532120395f6e797c (patch)
tree2fe9db8a4ecfa92d854ca94f7586d81163c8bd25 /src/views/Authorization/LoginView.jsx
downloaddonetick-frontend-2657469964e24ffbeb905024532120395f6e797c.tar.gz
donetick-frontend-2657469964e24ffbeb905024532120395f6e797c.tar.bz2
donetick-frontend-2657469964e24ffbeb905024532120395f6e797c.zip
move to Donetick Org, First commit frontend
Diffstat (limited to 'src/views/Authorization/LoginView.jsx')
-rw-r--r--src/views/Authorization/LoginView.jsx345
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