Material UI with Login Template with React.js - reactjs

I'm brand new to Material UI. I am currently trying to implement it into my project. Unfortunately, it's not cooperating. I think I am putting in everything right, but because I have never used MUI before, I am not sure. Can someone please help me figure out where the error is? I have tried multiple times, putting in the code I had before I tried to implement MUI. Thank you!
I will include the code before I tried to implement MUI, and after. The first is before MUI implementation. The last block of code is my Auth.jsx file.
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
export default function Login({ updateToken, toggleView }) {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const handleUsername = (e) => setUsername(e.target.value);
const handlePassword = (e) => setPassword(e.target.value);
const history = useHistory();
const handleSubmit = async (e) => {
e.preventDefault();
try {
const fetchResults = await fetch(`http://localhost:3001/user/`, {
method: "POST",
body: JSON.stringify({ username, password }),
headers: new Headers({
"Content-Type": "application/json",
}),
});
const json = await fetchResults.json();
if (!json.user || !json.sessionToken) {
alert(json.message);
return;
}
updateToken(json.sessionToken);
history.push("/home");
} catch (err) {
console.error(err);
}
};
return (
<div>
<div className='signin'>
<form onSubmit={handleSubmit}>
<input
type='username'
onChange={handleUsername}
name='username'
placeholder='Username'
required
value={username}
className='signin__input'
/>
<input
type='password'
onChange={handlePassword}
name='password'
placeholder='Password'
type='password'
required
value={password}
className='signin__input'
/>
<button className='login__button' type='submit'>
Login
</button>
</form>{" "}
<p className='signin__toggle' onClick={() => history.push("./signup")}>
Don't have an account? Sign up here.{" "}
</p>
</div>
</div>
);
}
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import Avatar from "#mui/material/Avatar";
import Button from "#mui/material/Button";
import CssBaseline from "#mui/material/CssBaseline";
import TextField from "#mui/material/TextField";
import FormControlLabel from "#mui/material/FormControlLabel";
import Checkbox from "#mui/material/Checkbox";
import Link from "#mui/material/Link";
import Grid from "#mui/material/Grid";
import Box from "#mui/material/Box";
import LockOutlinedIcon from "#mui/icons-material/LockOutlined";
import Typography from "#mui/material/Typography";
import Container from "#mui/material/Container";
import { createTheme, ThemeProvider } from "#mui/material/styles";
function Copyright(props) {
return (
<Typography
variant='body2'
color='text.secondary'
align='center'
{...props}
>
{"Copyright © "}
<Link color='inherit' href='https://courtney-downs.web.app/'>
Courtney Downs Portfolio
</Link>{" "}
{new Date().getFullYear()}
{"."}
</Typography>
);
}
const theme = createTheme();
export default function Login2({ updateToken, toggleView }) {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const handleUsername = (e) => setUsername(e.target.value);
const handlePassword = (e) => setPassword(e.target.value);
const history = useHistory();
const handleSubmit = async (e) => {
e.preventDefault();
try {
const fetchResults = await fetch(`http://localhost:3001/user/`, {
method: "POST",
body: JSON.stringify({ username, password }),
headers: new Headers({
"Content-Type": "application/json",
}),
});
const json = await fetchResults.json();
if (!json.user || !json.sessionToken) {
alert(json.message);
return;
}
updateToken(json.sessionToken);
history.push("/home");
} catch (err) {
console.error(err);
}
};
return (
<ThemeProvider theme={theme}>
<Container component='main' maxWidth='xs'>
<CssBaseline />
<Box
sx={{
marginTop: 8,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Avatar sx={{ m: 1, bgcolor: "secondary.main" }}>
<LockOutlinedIcon />
</Avatar>
<Typography component='h1' variant='h5'>
Sign in
</Typography>
<Box
component='form'
onSubmit={handleSubmit}
noValidate
sx={{ mt: 1 }}
>
<TextField
margin='normal'
required
fullWidth
id='username'
label='Username'
name='username'
autoComplete='username'
value={username}
onChange={handleUsername}
autoFocus
/>
<TextField
margin='normal'
required
fullWidth
name='password'
label='Password'
type='password'
id='password'
value={password}
onChange={handlePassword}
autoComplete='current-password'
/>
<FormControlLabel
control={<Checkbox value='remember' color='primary' />}
label='Remember me'
/>
<Button
type='submit'
fullWidth
variant='contained'
sx={{ mt: 3, mb: 2 }}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link href='#' variant='body2'>
Forgot password?
</Link>
</Grid>
<Grid item>
<Link onClick={toggleView} variant='body2'>
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</Box>
</Box>
<Copyright sx={{ mt: 8, mb: 4 }} />
</Container>
</ThemeProvider>
);
}
import React, { useState } from "react";
import Login2 from "./Login2";
import Signup from "./Signup";
export default function Auth({ sessionToken, updateToken }) {
const [loginShowing, setLoginShowing] = useState(true);
const toggleView = () => setLoginShowing(!loginShowing);
return (
<div>
{loginShowing ? (
<Login2
token={sessionToken}
updateToken={updateToken}
toggleView={toggleView}
/>
) : (
<Signup
updateToken={updateToken}
token={sessionToken}
toggleView={toggleView}
/>
)}
</div>
);
}

Related

ReactJS with Firebase, also using React Redux for login of user and how for the admin

The code below is the login output wherein the user and the admin use it as the entry way into the website. There is no problem to the logging in of the user and the admin but the only problem is how to redirect the admin after the login to the website which will redirect to the admin dashboard home?
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link, useHistory } from "react-router-dom";
import {
emailSignInStart,
googleSignInStart,
} from "./../../Redux/User/user.actions";
import "./style.scss";
import ButtonForm from "./../Forms/Button";
import {
Typography,
Divider,
IconButton,
TextField,
Tooltip,
} from "#material-ui/core";
import { FaFacebook, FaGoogle, FaMailBulk } from "react-icons/fa";
import Visibility from "#material-ui/icons/Visibility";
import VisibilityOff from "#material-ui/icons/VisibilityOff";
const mapState = ({ user }) => ({
currentUser: user.currentUser,
}); //to get from the redux store
const SigninIn = (props) => {
const dispatch = useDispatch();
const history = useHistory();
const { currentUser } = useSelector(mapState);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [errors, setErrors] = useState([]);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
//whenever signinsuccess is true
if (currentUser) {
resetForm();
history.push("/");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentUser]);
const resetForm = () => {
setEmail("");
setPassword("");
setErrors([]);
};
const handleSubmit = (e) => {
e.preventDefault();
dispatch(emailSignInStart({ email, password }));
setIsLoading(true);
};
const handleGoogleSignIn = () => {
dispatch(googleSignInStart());
};
return (
<div className="container">
<div className="wrap">
<h2>Log in</h2>
<div className="formWrap">
<form onSubmit={handleSubmit}>
<div className="grouped">
<TextField
autoFocus
margin="dense"
type="email"
label="Email"
color="secondary"
fullWidth
variant="outlined"
onChange={(e) => setEmail(e.target.value)}
required
/>
<br></br>
{/* {Might use this for password validation - https://www.npmjs.com/package/material-ui-password-field} */}
<TextField
margin="dense"
type="password"
label="Password"
fullWidth
color="secondary"
variant="outlined"
helperText="Password must be more than 6 characters long"
onChange={(e) => setPassword(e.target.value)}
required
/>
<Link to="/recovery">
<Typography align="center" variant="subtitle1" display="block">
Forgot Password?
</Typography>
</Link>
<br></br>
<ButtonForm type="submit" className="btn">
{isLoading ? (
<p>
{" "}
<Typography variant="h6" align="center"
display="block">
Logging In...
</Typography>
</p>
) : (
<Typography variant="h6" align="center" display="block">
Log In
</Typography>
)}
</ButtonForm>
<br></br>
<Divider />
<Typography variant="subtitle2" align="center" display="block">
Or Continue with
</Typography>
<div className="socialSignin">
<div className="row">
<Tooltip title="Continue with Google">
<IconButton
onClick={handleGoogleSignIn}
aria-label="googleSignIn"
>
<FaGoogle
style={{
color: "#EA4335",
fontSize: "30px",
}}
/>
</IconButton>
</Tooltip>
<Tooltip title="Register with email">
<Link to="/registration">
<IconButton aria-label="mailRegister">
<FaMailBulk
style={{
color: "#e31837",
fontSize: "30px",
}}
/>
</IconButton>
</Link>
</Tooltip>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
);
};
export default SigninIn;
How can I solve it into making the redirecting of the page after login directly to the admin page? How can I do it with some use of React Router, React Redux and other parts of ReactJS wherein that it will redirect the admin directly to the page of the admin as a landing page.

Probleme with Reach-hook-form validation on update

I Working with hook-form and MaterialUI, I want to make the validation of the form, the validation working well in adding, but on update (input are ready full) in shows me erros (inputs are empty):
my code:
import Box from "#mui/material/Box";
import Button from "#mui/material/Button";
import Grid from "#mui/material/Grid";
import TextField from "#mui/material/TextField";
import axios from "axios";
import "bootstrap/dist/css/bootstrap.min.css";
import React from "react";
import { useForm } from "react-hook-form";
import { useNavigate, useParams } from "react-router-dom";
function UpdateEmployer(props) {
const { id } = useParams();
const { register, handleSubmit, formState, control } = useForm({
mode: "onChange",
});
// declare states
const [FullName, setFullName] = React.useState("");
const [cin, setCin] = React.useState("");
const [profile, setProfile] = React.useState("");
const [years, setYears] = React.useState("");
const { isSubmitting, errors, isValid } = formState;
const navigate = useNavigate();
// get data from form and post to api
const onSubmit = async (data) => {
// set state from data
const { FullName, cin, profile, years } = data;
console.log(data);
await axios.put(`http://localhost:5000/employers/${id}`, {
fullname: FullName,
cin: cin,
profile: profile,
experience: years,
});
navigate("/");
};
React.useEffect(() => {
axios.get(`http://localhost:5000/employers/${id}`).then((res) => {
setFullName(res.data.fullname);
setCin(res.data.cin);
setProfile(res.data.profile);
setYears(res.data.experience);
});
}, []);
// -------------------- render componenet --------------------
return (
<div className="container mt-4">
<div className="text-center my-3 font-weight-bold">Update Employer</div>
<form onSubmit={handleSubmit(onSubmit)} style={{ width: "100%" }}>
<Grid container spacing={2}>
<Grid item xs={8}>
<TextField
id="FullName"
name="FullName"
label="Full Name"
variant="outlined"
fullWidth
value={FullName}
{...register("FullName", { required: "Please Entre your name" })}
onChange={(e) => setFullName(e.target.value)}
/>
<span className="text-danger">
{errors.FullName && errors.FullName.message}
</span>
</Grid>
<Grid item xs={4}>
<TextField
id="cin"
name="cin"
label="CIN"
variant="outlined"
value={cin}
fullWidth
{...register(
"cin",
{ required: "Please Entre your cin" },
{
minLength: {
value: 6,
message: "Oops! the cin have to ve at least 6 characters",
},
}
)}
onChange={(e) => {
console.log(e.target.value);
setCin(e.target.value);
}}
/>
<span className="text-danger">
{errors.cin && errors.cin.message}
</span>
</Grid>
<Grid item xs={8}>
<TextField
id="profile"
name="profile"
label="Profile"
variant="outlined"
fullWidth
value={profile}
{...register("profile", {
required: "Please Entre your profile",
})}
onChange={(e) => setProfile(e.target.value)}
/>
</Grid>
<Grid item xs={4}>
<TextField
id="years"
name="years"
label="Years of Experience"
variant="outlined"
value={years}
fullWidth
{...register("years", { required: "Please Entre your years" })}
onChange={(e) => setYears(e.target.value)}
/>
</Grid>
<Grid item xs={12}>
<Box textAlign="center">
<Button
id="Update_employer"
variant="contained"
color="primary"
type="submit"
// disabled={!isValid}
>
Update Employee
</Button>
</Box>
</Grid>
</Grid>
</form>
</div>
);
}
export default UpdateEmployer;
The fill he inputs in with useEffect() and it shows me that the input are full with the right information but when I want to submit it shows me that error that the input are empty.

White blank screen when I try to use AuthProvider and useAuth (react + firebase)

I'm trying to set up my firebase authorization but keep running into the same problem. I'm not sure why, but for some reason, I get a white blank screen whenever I put AuthProvider around my components, my router, anything. As soon as I comment it out, my login and register pages pop back up again. Any help would be greatly appreciated.
I've gone through my code for hours and can't find the issue. I'm hoping it's something small that I'm missing, but really hope someone can help.
Also, I'm using Material-UI (though I doubt that makes a difference) and I have all of my API keys and such in a .env file (I have 3x checked that they're all correct).
Anyway, here's my authentication.js code:
import React, { useEffect, useState } from "react";
import app from "./firebase";
export const AuthContext = React.createContext();
export const AuthProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
const [pending, setPending] = useState(true);
useEffect(() => {
app.auth().onAuthStateChanged((user) => {
setCurrentUser(user)
setPending(false)
});
}, []);
if(pending){
return <>Please wait...</>
}
return (
<AuthContext.Provider
value={{
currentUser
}}
>
{children}
</AuthContext.Provider>
);
};
I also tried this way in my context folder:
import React, { useContext, useState, useEffect } from 'react';
import { auth } from '../firebase';
const AuthContext = React.createContext()
export function useAuth(){
return useContext(AuthContext)
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState(null)
function register(email, password) {
return auth.createUserWithEmailAndPassword(email, password)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
setCurrentUser(user)
})
return unsubscribe
}, [])
const value = {
currentUser,
register
}
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
)
}
And here's my App.js code:
import React from 'react';
import 'fontsource-roboto';
import { BrowserRouter as Router, Route } from "react-router-dom";
import Home from './Home';
import Login from './Login';
import Register from './Register'
// import { AuthProvider } from '../authentication';
function App(){
return (
// <AuthProvider>
<Router>
<div>
<Route exact path="/" component={Home} />
<Route exact path="/login" component={Login} />
<Route exact path="/Register" component={Register} />
</div>
</Router>
// </AuthProvider>
)
}
export default App;
And my Register page if that helps:
import React, { useRef } from 'react';
import Avatar from '#material-ui/core/Avatar';
import Button from '#material-ui/core/Button';
import CssBaseline from '#material-ui/core/CssBaseline';
import TextField from '#material-ui/core/TextField';
import Link from '#material-ui/core/Link';
import Paper from '#material-ui/core/Paper';
import Grid from '#material-ui/core/Grid';
import Box from '#material-ui/core/Box';
import LockOutlinedIcon from '#material-ui/icons/LockOutlined';
import Typography from '#material-ui/core/Typography';
// import { Alert } from '#material-ui/lab';
import { makeStyles } from '#material-ui/core/styles';
// import { useAuth } from '../contexts/AuthContext';
// import register from '../contexts/AuthContext'
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://kindredcompanion.app/">
Kindred Companion App
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
const useStyles = makeStyles((theme) => ({
root: {
height: '100vh',
},
image: {
// VTM Banner
backgroundImage: 'url(https://res.cloudinary.com/think-halcyon-llc/image/upload/v1617055998/Vampire:%20the%20Masquerade/vtm_banner_qze9dn.png)',
backgroundRepeat: 'no-repeat',
backgroundColor:
theme.palette.type === 'light' ? theme.palette.grey[50] : theme.palette.grey[900],
backgroundSize: 'cover',
backgroundPosition: 'center',
},
paper: {
margin: theme.spacing(8, 4),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(1),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
export default function Register() {
const classes = useStyles();
const firstNameRef = useRef()
const lastNameRef = useRef()
const emailRef = useRef()
const passwordRef = useRef()
const passwordConfirmRef = useRef()
// const { register } = useAuth()
// const [error, setError] = useState("")
// const [loading, setLoading] = useState(false)
// async function handleSubmit(e) {
// e.preventDefault()
// if (passwordRef.current.value !== passwordConfirmRef.current.value) {
// return setError("Passwords do not match.")
// }
// try {
// setError("")
// setLoading(true)
// await register(emailRef.current.value, passwordRef.current.value)
// } catch {
// setError("Failed to create an account.")
// }
// setLoading(false)
// }
return (
<Grid container component="main" className={classes.root}>
<CssBaseline />
<Grid item xs={false} sm={4} md={7} className={classes.image} />
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Register
</Typography>
<br />
{/* {error && <Alert severity="error">{error}</Alert>} */}
<form
className={classes.form}
// onSubmit={handleSubmit}
>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
autoComplete="fname"
name="firstName"
variant="outlined"
required
fullWidth
id="firstName"
label="First Name"
inputRef={firstNameRef}
autoFocus
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
variant="outlined"
required
fullWidth
id="lastName"
label="Last Name"
name="lastName"
inputRef={lastNameRef}
autoComplete="lname"
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="email"
label="Email Address"
name="email"
inputRef={emailRef}
autoComplete="email"
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
inputRef={passwordRef}
autoComplete="current-password"
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password-confirm"
label="Password Confirmation"
type="password"
id="password"
inputRef={passwordConfirmRef}
autoComplete="current-password"
/>
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
// disabled={loading}
>
Sign Up
</Button>
<Grid container justify="flex-end">
<Grid item>
<Link href="/login" variant="body2">
Already have an account? Sign in
</Link>
</Grid>
</Grid>
<Box mt={5}>
<Copyright />
</Box>
</form>
</div>
</Grid>
</Grid>
);
}
Hoping someone can help me!
I actually had this issue too. My .env file was configured wrong and Firebase threw me an error where it said Invalid API key. Hopefully this helps!

trouble making firebase authcheck with express/mongodb server from react

I am working on a project that requires firebase authorization with a custom server. I am using mongodb with express and mongoose. Client side is react. The trouble i am having can be seen using the login page as an example.
import React, { useState, useEffect } from 'react'
import {NavLink} from 'react-router-dom'
import axios from 'axios'
import * as Yup from 'yup';
import { Formik, Form, Field } from 'formik';
import {
CssBaseline,
Box,
Divider,
Container,
Card,
CardContent,
InputAdornment,
Icon,
IconButton,
Avatar,
FormHelperText,
Button,
TextField,
Link,
Grid,
Typography,
} from '#material-ui/core';
import Visibility from '#material-ui/icons/Visibility'
import VisibilityOff from '#material-ui/icons/VisibilityOff'
import { auth, googleAuthProvider } from '../../../firebase'
import { useSnackbar } from 'notistack'
import LockOutlinedIcon from '#material-ui/icons/LockOutlined';
import useStyles from './login-styles'
import googleIcon from '../../../assets/google.svg'
import useMediaQuery from '#material-ui/core/useMediaQuery';
import { useTheme } from '#material-ui/core/styles';
import { useDispatch, useSelector } from 'react-redux'
import useIsMountedRef from '../../../hooks/useIsMountedRef'
import AuthPage from '../AuthPage'
const initialValues = {
email: '',
password: ''
}
const validationSchema = Yup.object({
email: Yup.string().email().max(255).required(),
password: Yup.string().min(7).max(255).required('Password is required')
})
const createOrUpdateUser = async (authtoken) => {
return await axios.post(`${process.env.REACT_APP_API}/create-or-update-user`, {}, {
headers: {
authtoken
}
})
}
const Login = ({history}) => {
let dispatch = useDispatch()
const theme = useTheme();
const {user} = useSelector((state) => ({...state}))
const {enqueueSnackbar} = useSnackbar()
const classes = useStyles();
const isMountedRef = useIsMountedRef();
const isMobile = useMediaQuery(theme.breakpoints.down('xs'));
const [passwordVisible, setPasswordVisible] = useState(false)
const togglePasswordVisibility = () => {
setPasswordVisible({ passwordVisible : !passwordVisible})
}
useEffect(() => {
if (user && user.token) {
history.push('/client-dash')
}
}, [user])
const handleGoogleClick = async () => {
auth.signInWithPopup(googleAuthProvider)
.then(async(result) => {
const { user } = result
const idTokenResult = await user.getIdTokenResult();
createOrUpdateUser(idTokenResult.token)
.then(res => console.log(' CREATE OR UPDATE RESPONSE', res))
.catch()
//send snackbar success email sent
enqueueSnackbar(`Welcome back, ${user.displayName}!`, {
variant: 'success'
})
// dispatch({
// type: 'LOGGED_IN_USER',
// payload: {
// email: user.email,
// token: idTokenResult,
// }
// });
// history.push('/client-dash')
})
.catch((err) => {
console.log(err)
enqueueSnackbar((err.message), {
variant: 'error'
});
})
}
return (
<AuthPage>
<CardContent className="flex flex-col items-center justify-center w-full py-96 max-w-320">
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<Button
className={classes.googleButton}
fullWidth
onClick={handleGoogleClick}
size="large"
variant="contained"
>
<img
alt="Google"
className={classes.providerIcon}
src={googleIcon}
/>
Sign in with Google
</Button>
<Box
alignItems="center"
display="flex"
mt={2}
>
<Divider
style={{color: '#161616'}}
className={classes.divider}
orientation="horizontal"
/>
<Typography
style={{color: '#161616'}}
variant="body1"
className={classes.dividerText}
>
OR
</Typography>
<Divider
orientation="horizontal"
/>
</Box>
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={async(values, {
setErrors,
setStatus,
setSubmitting
}) => {
try {
const result = await auth.signInWithEmailAndPassword(values.email, values.password)
console.log(result);
const { user } = result
const idTokenResult = await user.getIdTokenResult()
createOrUpdateUser(idTokenResult.token)
.then(res => console.log(' CREATE OR UPDATE RESPONSE', res))
.catch()
//send snackbar success email sent
enqueueSnackbar(`Welcome back, ${user.displayName}!`, {
variant: 'success'
})
dispatch({
type: 'LOGGED_IN_USER',
payload: {
email: user.email,
token: idTokenResult,
}
});
if (isMountedRef.current) {
setStatus({ success: true });
setSubmitting(false);
history.push('/client-dash')
}
} catch (err) {
console.error(err);
enqueueSnackbar((err.message), {
variant: 'error'
});
if (isMountedRef.current) {
setStatus({ success: false });
setErrors({ submit: err.message });
setSubmitting(false);
}
}
}}>
{({ values,
errors,
handleBlur,
handleChange,
isSubmitting,
touched }) => (
<Form className={classes.form}>
<Field
name="email"
as={TextField}
error={Boolean(touched.email && errors.email)}
fullWidth
helperText={touched.email && errors.email}
label="Email Address"
margin="normal"
name="email"
onBlur={handleBlur}
onChange={handleChange}
type="email"
value={values.email}
variant='outlined'
autoFocus
InputProps={{
endAdornment: (
<InputAdornment position="end">
<Icon className="text-20" color="action">
mail
</Icon>
</InputAdornment>
)
}}
/>
<Field
as={TextField}
error={Boolean(touched.password && errors.password)}
fullWidth
helperText={touched.password && errors.password}
label="Password"
margin="normal"
name="password"
onBlur={handleBlur}
onChange={handleChange}
type={passwordVisible ? 'text' : 'password'}
value={values.password}
variant="outlined"
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
className="focus:outline-none"
aria-label="toggle password visible"
onClick={togglePasswordVisibility}
edge="end">
{passwordVisible ? <Visibility/> : <VisibilityOff/>}
</IconButton>
</InputAdornment>
)
}}
/>
{errors.submit && (
<Box mt={3}>
<FormHelperText error>
{errors.submit}
</FormHelperText>
</Box>
)}
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
disabled={(Object.keys(touched).length === 0 && touched.constructor === Object) || isSubmitting}
className={classes.submit}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link component={NavLink} to="/forgot-password" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link component={NavLink} to="/create-account" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</Form>
)}
</Formik>
</div>
</CardContent>
</AuthPage>
)
}
export default Login
the firebase function in handled in the onSubmit fuction. It sends the token to endpoint in the server.
const express = require('express')
const router = express.Router()
//import middleware
const {authCheck} = require("../middleware/auth")
//import controllers
const {createOrUpdateUser} = require("../controllers/auth")
//route
router.post('/create-or-update-user', authCheck, createOrUpdateUser)
module.exports = router;
i am using the authcheck middleware to verify the token.
const admin = require('../firebase');
exports.authCheck = async (req, res, next) => {
console.log(req.headers.authtoken); //token
try {
const firebaseUser = await admin.auth().verifyIdToken(req.headers.authtoken);
console.log('FIREBASE USER IN AUTHCHECK', firebaseUser)
req.user = firebaseUser;
next();
} catch (err) {
console.log(err)
// res.status(401).json({
// err: "Invalid or expired token",
// });
}
};
however this returns a 401 token expired. i know the token is being sent because it is logged in the console. Im at a loss. i dont see any other way to write the code.
I found the answer here on stack overflow. A simple time sync on the machine i am working on did the trick.
Error: Firebase ID token has expired

How to add validation in a login page in reactjs

I'm fairly new and can't seem to find a way to properly add validation to my login form. All I could do is add required so that it won't call the api when the fields are empty. I would also like to add email validation that it should contain '#' and password validation for like 6 characters and numbers and symbols. I tried following some tutorials but they seem way too complicated and I can't seem to find a way to call the performLogin function along with the validation functions using the tutorials. This is the tutorial that I was following by the way.
I tried this in codesandbox so far, can someone please show where to add the validations exactly?
import React, { useState } from "react";
import Avatar from "#material-ui/core/Avatar";
import Button from "#material-ui/core/Button";
import CssBaseline from "#material-ui/core/CssBaseline";
import TextField from "#material-ui/core/TextField";
import Link from "#material-ui/core/Link";
import Grid from "#material-ui/core/Grid";
import Box from "#material-ui/core/Box";
import LockOutlinedIcon from "#material-ui/icons/LockOutlined";
import Typography from "#material-ui/core/Typography";
import { makeStyles } from "#material-ui/core/styles";
import Container from "#material-ui/core/Container";
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
<Link color="inherit" href="">
Hello
</Link>{" "}
{new Date().getFullYear()}
{"."}
</Typography>
);
}
const useStyles = makeStyles(theme => ({
paper: {
marginTop: theme.spacing(8),
display: "flex",
flexDirection: "column",
alignItems: "center"
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main
},
form: {
width: "100%",
marginTop: theme.spacing(1)
},
submit: {
margin: theme.spacing(3, 0, 2)
}
}));
export default function Login(props) {
const classes = useStyles();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const performLogin = async event => {
event.preventDefault();
var body = {
password: password,
email: email
};
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: JSON.stringify(body)
};
const url = "/api/authenticate";
try {
const response = await fetch(url, options);
const text = await response.text();
if (text === "redirect") {
props.history.push(`/editor`);
} else if (text === "verifyemail") {
props.history.push(`/verifyOtp/${this.state.email}`);
} else {
console.log("login failed");
window.alert("login failed");
}
} catch (error) {
console.error(error);
}
};
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form} onSubmit={performLogin}>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
onChange={e => setEmail(e.target.value)}
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
onChange={e => setPassword(e.target.value)}
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
{/* <Link href="#" variant="body2">
Forgot password?
</Link> */}
</Grid>
<Grid item>
<Link href="/register" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={8}>
<Copyright />
</Box>
</Container>
);
}
the problem is that most tutorials/guides won't show exactly where to call the login function and just do some console logging in handleSubmit and I'm really confused there.
A simple way to do this would be to validate things in the performLogin method, prior to setting the body variable, then error out if it's not valid. So you can do the following:
Add a variable to track the error state:
const [error, setError] = useState("");
Add this to performLogin right before var body = {...}
//Validate Password
if(email.indexOf("#") <= 0){
setError("Email address must contain an #.");
return; //don't log in
}
else{
setError(null); //no error
}
Then display the error in your view if there is one. Add this right before the <form...> in your render method:
{error &&
<div style={{color: "red"}}>
<span>{error}</span>
</div>
}
If I forked it right, this CodeSandbox should show the changes.
This is just a basic example for performing the validation in a very simple way. For more advanced, involved validation, I'd break it out into a separate function, or even a separate component (e.g. EmailInput). But this should give you enough to keep moving forward.

Resources