Can't verify Email and Password data from Firebase Auth - reactjs

So I've linked my app to a Firebase project and I've created a login form. I'm trying to get the data from the Email and Password inputs and verify it with whats in the Firebase project but for some reason the data isn't being received by Firebase, I was able to achieve it perfectly earlier but now I don't know whats going on...
App.js
import style from "./auth.module.css";
import { useEffect, useRef, useState } from "react";
import { useAuthState } from 'react-firebase-hooks/auth';
import { auth, signInWithEmailAndPassword, signInWithGoogle, registerWithEmailAndPassword } from "../../firebase";
import { CSSTransition } from "react-transition-group";
const Auth = () => {
const [activeMenu, setActiveMenu] = useState("main");
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [user, loading, error] = useAuthState(auth);
const Emailform = () => {
return (
<div className={style.formBox}>
<label className={style.label}>Email:</label>
<form className={style.input}>
<input
type="email"
name="email"
required="true"
/>
</form>
</div>
);
}
const Passform = () => {
return (
<div className={style.formBox}>
<label className={style.label}>Password:</label>
<form className={style.input}>
<input
type="password"
name="password"
required="true" />
</form>
</div>
);
}
let domNode = useClickOutside(() => {
setActiveMenu(false);
});
return (
<div className={style.container}>
<Login />
<Signup />
</div>
);
function AuthType(props) {
return (
<a
href={props.link}
className={style.menuItem}
onClick={() => props.goToMenu && setActiveMenu(props.goToMenu)}
>
{props.children}
</a>
);
}
/* Login */
function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
return (
<CSSTransition in={activeMenu === "main"} unmountOnExit timeout={500}>
<div ref={domNode}>
<div className={style.login}>
<h1 className={style.title}>Clip It</h1>
{/* Email and Password */}
<Emailform value={email} onChange={(e) => setEmail(e.target.value)}/>
<Passform value={password} onChange={(e) => setPassword(e.target.value)}/>
<div className={style.button}>
<input
type="submit"
value="Login"
onClick={() => signInWithEmailAndPassword(email, password)} />
<input
type="submit"
value="Login with Google"
onClick={signInWithGoogle} />
</div>
<div className={style.text}>
<p className={style.plink}>Forgot Password</p>
<div>
Need an account?
<AuthType goToMenu="Signup">click here</AuthType>
</div>
</div>
</div>
</div>
</CSSTransition>
);
}
/* SignUp/Register */
function Signup() {
return (
<CSSTransition in={activeMenu === "Signup"} unmountOnExit timeout={500}>
<div ref={domNode}>
<div className={style.signUp}>
<div className={style.title}> Clip It</div>
<Form label="First Name" type="text" />
<Form label="Last Name" type="Text" />
<Emailform value={email} onChange={(e) => setEmail(e.target.value)}/>
<Form label="Date of Birth" type="date" />
<Passform value={password} onChange={(e) => setPassword(e.target.value)}/>
<Form label="Confirm Password" type="password" />
<div className={style.button}>
<input
type="submit"
value="Sign Up"
onClick={registerWithEmailAndPassword} />
</div>
<div className={style.text}>
have an
<AuthType goToMenu="main"> account</AuthType>
</div>
</div>
</div>
</CSSTransition>
);
}
}
let useClickOutside = (handler) => {
let domNode = useRef();
useEffect(() => {
let clickListener = (event) => {
if (domNode.current && !domNode.current.contains(event.target)) {
handler();
}
};
document.addEventListener("mousedown", clickListener);
return () => {
document.removeEventListener("mousedown", clickListener);
};
});
return domNode;
};
function Form(props) {
return (
<div className={style.formBox}>
<label className={style.label}>{props.label}:</label>
<form className={style.input}>
<input
type={props.input}
name={props.input}
required="true" />
</form>
</div>
);
}
export default Auth;
Firebase.js
import firebase from 'firebase/app';
//import * as firebase from "firebase/app";
import "firebase/auth"
import "firebase/firestore"
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "AIzaSyCq8BAlTWJXG7rFU95QkUTU8U0kXruPA9o",
authDomain: "clip-it-70ff5.firebaseapp.com",
databaseURL: "https://clip-it-70ff5-default-rtdb.firebaseio.com",
projectId: "clip-it-70ff5",
storageBucket: "clip-it-70ff5.appspot.com",
messagingSenderId: "637963668511",
appId: "1:637963668511:web:9cbd1deae03b819153d92a",
measurementId: "G-8S1G78ZH49"
};
const app = !firebase.apps.length ? firebase.initializeApp(firebaseConfig) : firebase.app();
const auth = app.auth();
const db = app.firestore();
/* Using Google Authentication */
const googleProvider = new firebase.auth.GoogleAuthProvider();
//
const signInWithGoogle = async () => {
try {
await auth.signInWithPopup(googleProvider).then((res) => {
const user = res.user;
const userName = user.displayName;
alert("You're logged in " + userName);
});
}
catch (err) {
console.error(err);
alert(err.message);
}
};
/* Using Email and Password */
// Sign/Logging In
const signInWithEmailAndPassword = async (email, password) => {
try {
await auth.signInWithEmailAndPassword(email.trim(), password);
alert("You've logged in successfuly");
} catch (err) {
console.error(err);
alert("The email or password is incorrect, please try again");
}
};
//SigningUp
const registerWithEmailAndPassword = async (email, password) => {
try {
const res = await auth.createUserWithEmailAndPassword(email, password);
const user = res.user;
await db.collection("users").add({
uid: user.uid,
authProvider: "local",
email,
});
alert("New user added!");
} catch (err) {
console.error(err);
alert(err.message);
}
};
//Sending Password reset link
const sendPasswordResetEmail = async (email) => {
try {
await auth.sendPasswordResetEmail(email);
alert("Password reset link sent!");
} catch (err) {
console.error(err);
alert(err.message);
}
};
const logout = () => {
auth.signOut();
}; // Log out
export {
signInWithGoogle,
signInWithEmailAndPassword,
registerWithEmailAndPassword,
sendPasswordResetEmail,
logout,
auth,
db,
};

You're still assigning props to your Emailform/Passform components in your Login component which you never actually access. So you're never actually setting the state of email or password.
Remove all of the props and rewrite Emailform/Passform like this:
const Emailform = () => {
return (
<div className={style.formBox}>
<label className={style.label}>Email:</label>
<form className={style.input}>
<input
type="email"
name="email"
required="true"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</form>
</div>
);
}
const Passform = () => {
return (
<div className={style.formBox}>
<label className={style.label}>Password:</label>
<form className={style.input}>
<input
type="password"
name="password"
required="true"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</form>
</div>
);
}

Related

Can't verify email and password from Firebase

I'm creating a signup form and trying to get the email and password to work. When I used input and set the state with the appropriate values, it works just fine, but once I wrap the Input around my custom component its unable to get data from the component into the state and gives me an error that a user cannot be found (even if their info is in the Firebase Auth)
I need help.
Auth.js
import style from "./auth.module.css";
import { useEffect, useRef, useState } from "react";
import { useAuthState } from 'react-firebase-hooks/auth';
import { auth, signInWithEmailAndPassword, signInWithGoogle } from "../../firebase";
import { CSSTransition } from "react-transition-group";
export default function Auth() {
const [activeMenu, setActiveMenu] = useState("main");
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [user, loading, error] = useAuthState(auth);
let domNode = useClickOutside(() => {
setActiveMenu(false);
});
return (
<div className={style.container}>
<Login />
<Signup />
</div>
);
function AuthType(props) {
return (
<a
href={props.link}
className={style.menuItem}
onClick={() => props.goToMenu && setActiveMenu(props.goToMenu)}
>
{props.children}
</a>
);
}
/* I believe you've switched up the login and sign-up? */
function Login() {
return (
<CSSTransition in={activeMenu === "main"} unmountOnExit timeout={500}>
<div ref={domNode}>
<div className={style.login}>
<h1 className={style.title}>Clip It</h1>
{/* Email and Password */}
<Emailform
label="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<Passform
label="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<div className={style.button}>
<input
type="submit"
value="Login"
onClick={() => signInWithEmailAndPassword(email, password)} />
<input
type="submit"
value="Login with Google"
onClick={signInWithGoogle} />
</div>
<div className={style.text}>
<p className={style.plink}>Forgot Password</p>
<div>
Need an account?
<AuthType goToMenu="Signup">click here</AuthType>
</div>
</div>
</div>
</div>
</CSSTransition>
);
}
function Signup() {
return (
<CSSTransition in={activeMenu === "Signup"} unmountOnExit timeout={500}>
<div ref={domNode}>
<div className={style.signUp}>
<div className={style.title}> Clip It</div>
<Form label="First Name" type="text" />
<Form label="Last Name" type="Text" />
<Form label="Email" type="email" />
<Form label="Date of Birth" type="date" />
<Form label="Password" type="password" />
<Form label="Confirm Password" type="password" />
<div className={style.button}>
<input type="submit" value="Sign Up" />
</div>
<div className={style.text}>
have an
<AuthType goToMenu="main"> account</AuthType>
</div>
</div>
</div>
</CSSTransition>
);
}
}
let useClickOutside = (handler) => {
let domNode = useRef();
useEffect(() => {
let clickListener = (event) => {
if (domNode.current && !domNode.current.contains(event.target)) {
handler();
}
};
document.addEventListener("mousedown", clickListener);
return () => {
document.removeEventListener("mousedown", clickListener);
};
});
return domNode;
};
function Form(props) {
return (
<div className={style.formBox}>
<label className={style.label}>{props.label}:</label>
<form className={style.input}>
<input
type={props.input}
name={props.input}
required="true" />
</form>
</div>
);
}
function Emailform(props) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
return (
<div className={style.formBox}>
<label className={style.label}>{props.label}:</label>
<form className={style.input}>
<input
type="email"
name={props.input}
required="true"
value={email}
onChange={(e) => setEmail(e.target.value)} />
</form>
</div>
);
}
function Passform(props) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
return (
<div className={style.formBox}>
<label className={style.label}>{props.label}:</label>
<form className={style.input}>
<input
type="text"
name={props.input}
required="true"
value={password}
onChange={(e) => setPassword(e.target.value)} />
</form>
</div>
);
}
Firebase.js
import firebase from 'firebase/app';
//import * as firebase from "firebase/app";
import "firebase/auth"
import "firebase/firestore"
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "AIzaSyCq8BAlTWJXG7rFU95QkUTU8U0kXruPA9o",
authDomain: "clip-it-70ff5.firebaseapp.com",
databaseURL: "https://clip-it-70ff5-default-rtdb.firebaseio.com",
projectId: "clip-it-70ff5",
storageBucket: "clip-it-70ff5.appspot.com",
messagingSenderId: "637963668511",
appId: "1:637963668511:web:9cbd1deae03b819153d92a",
measurementId: "G-8S1G78ZH49"
};
const app = !firebase.apps.length ? firebase.initializeApp(firebaseConfig) : firebase.app();
const auth = app.auth();
const db = app.firestore();
/* Using Google Authentication */
const googleProvider = new firebase.auth.GoogleAuthProvider();
//
const signInWithGoogle = async () => {
try {
const res = await auth.signInWithPopup(googleProvider);
const user = res.user;
const query = await db
.collection("users")
.where("uid", "==", user.uid)
.get();
if (query.docs.length === 0) {
await db.collection("users").add({
uid: user.uid,
name: user.displayName,
authProvider: "google",
email: user.email,
});
alert("You're logged in");
}
} catch (err) {
console.error(err);
alert(err.message);
}
};
/* Using Email and Password */
// Sign/Logging In
const signInWithEmailAndPassword = async (email, password) => {
try {
await auth.signInWithEmailAndPassword(email.trim(), password);
alert("You've logged in successfuly");
} catch (err) {
console.error(err);
alert("The email or password is incorrect, please try again");
}
};
//SigningUp
const registerWithEmailAndPassword = async (name, email, password) => {
try {
const res = await auth.createUserWithEmailAndPassword(email.trim(), password);
const user = res.user;
await db.collection("users").add({
uid: user.uid,
name,
authProvider: "local",
email,
});
} catch (err) {
console.error(err);
alert(err.message);
}
};
//Sending Password reset link
const sendPasswordResetEmail = async (email) => {
try {
await auth.sendPasswordResetEmail(email);
alert("Password reset link sent!");
} catch (err) {
console.error(err);
alert(err.message);
}
};
const logout = () => {
auth.signOut();
}; // Log out
export {
signInWithGoogle,
signInWithEmailAndPassword,
registerWithEmailAndPassword,
sendPasswordResetEmail,
logout,
auth,
db,
};
Your code has a list of issues.
You have email/password states in both EmailForm/PassForm, as well as the parent (Auth) component.
You're setting values and trying to handle onChange on the EmailForm/PassForm components, but you never actually call these props, and you never actually set some of the props you're trying to access (ex: name={props.input}).
The inputs inside those two components are setting the email/password states to themselves, yet your Auth component is feeding Firebase its own states for email/password, which you never actually set.
You should also never use an input of type="text" for password fields.
If you insist on keeping the structure you currently have, move the EmailForm and PassForm functions inside to your Auth component, remove the props you're setting onto them, remove their states, and just use the Auth component's state.
// Inside the Auth component
const EmailForm = () => {
return (
<div className={style.formBox}>
<label className={style.label}>{props.label}:</label>
<form className={style.input}>
<input
type="email"
name="email"
required="true"
value={email}
onChange={(e) => setEmail(e.target.value)} />
</form>
</div>
);
}
const PassForm = () => {
return (
<div className={style.formBox}>
<label className={style.label}>{props.label}:</label>
<form className={style.input}>
<input
type="password"
name="password"
required="true"
value={password}
onChange={(e) => setPassword(e.target.value)} />
</form>
</div>
);
}
Then call them with a simple
<EmailForm />
<PassForm />

Two times click is necessary to Login in ReactJS

I am trying to make a Login page and I am successful in some way. So here is my Login component:
import React, { useState, useEffect } from "react";
import Axios from "axios";
import useForm from "../components/LoginForm/useForm";
import validate from "components/LoginForm/validate";
import redtruck from "../assets/img/red-truck.png";
import auth from "../Authentication/auth";
import { withRouter } from "react-router";
const Login = ({ submitForm, history }) => {
const [isSubmitted, setIsSubmitted] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [login, setLogin] = useState(false);
async function submitForm() {
setIsSubmitted(true);
try {
await fetchLogin(values.email, values.password);
if(login){
auth.login(() => {
history.push("/admin");
});
}
} catch (e) {
auth.login(() => {
history.push("/");
})
}
}
const { handleChange, values, handleSubmit, errors } = useForm(
submitForm,
validate
);
useEffect(() => {
if (localStorage.getItem("user-info")) {
submitForm();
}
}, []);
const fetchLogin = async (email, password) => {
try {
setLoading(true);
const res = await Axios({
method: "POST",
url: `url`,
headers: {
},
data: {
user_email: email,
user_password: password,
},
});
if (res.status === 200) {
setLogin(true);
localStorage.setItem("user-info", JSON.stringify(res.data));
}
setLoading(false);
} catch (err) {
setError(err.message);
setLoading(false);
}
};
return (
<>
<div>
<div className="form-container">
<div className="form-content-left">
<img className="form-img" src={redtruck} alt="spaceship" />
</div>
<div className="form-content-right">
<h1>SIGN IN</h1>
<form className="form" onSubmit={handleSubmit}>
<div className="form-inputs">
<label htmlFor="email" className="form-label">
Email address
</label>
<input
id="signin-email"
type="email"
name="email"
placeholder="Enter email"
className="form-input"
value={values.email}
onChange={handleChange}
/>
{errors.email && <p>{errors.email}</p>}
</div>
<div className="form-inputs">
<label htmlFor="password" className="form-label">
Password
</label>
<input
id="signin-password"
type="password"
name="password"
placeholder="Password"
className="form-input"
value={values.password}
onChange={handleChange}
/>
{errors.password && <p>{errors.password}</p>}
{login ? "" : <p>The password or the email is wrong</p>}
</div>
<button
variant="primary"
type="submit"
className="form-input-btn"
>
LOGIN
</button>
</form>
</div>
</div>
</div>
</>
);
};
export default withRouter(Login);
So the login state is set to true when email and password are right for the user. Later I want to use it when redirecting page to "/admin". But my problem is I have to click twice to login in the first place. Besides I am not sure, if the catch part is right:
catch (e) {
auth.login(() => {
history.push("/");
})
}
So I would be really glad, if you can give me some hint about it.
Thanks...
it is not that you have to press twice, you can check component state, sometimes React batches setState and then update value. You can look at this setState doesn't update the state immediately

Is it possible Preload a form with Firestore values?

I have a form that uploads its values to the Firestore database, and would like to use the same component for updating the values, so the question might really be - how to load initial state according to a conditional whether the props are passed?
The form
import Servis from "./funkc/servisni";
import React, { useState } from "react";
export default function ContactUpdate(props) {
//
console.log(props.item);
//
const initialState = {
id: props.item.id,
ime: props.item.Ime,
prezime: props.item.Prezime,
imeError: "",
prezimeError: "",
date: props.item.Datum,
kontakt: props.item.Kontakt,
kontaktError: "",
published: true,
};
const [theItem, setTheItem] = useState(initialState);
const [imeError, setImeError] = useState();
const [prezimeError, setPrezimeError] = useState();
const [message, setMessage] = useState();
const { item } = props;
if (theItem.id !== item.id) {
setTheItem(item);
}
const handleInputChange = (event) => {
const { name, value } = event.target;
setTheItem({ ...theItem, [name]: value });
};
const updatePublished = (status) => {
Servis.update(theItem.id0, { published: status })
.then(() => {
setTheItem({ ...theItem, published: status });
setMessage("The status was updated successfully!");
})
.catch((e) => {
console.log(e);
});
};
const updateItem = () => {
let data = {
Ime: theItem.ime,
Prezime: theItem.prezime,
Kontakt: theItem.kontakt,
Datum: theItem.date,
published: true,
};
Servis.update(theItem.id, data)
.then(() => {
setMessage("The tutorial was updated successfully!");
})
.catch((e) => {
console.log(e);
});
};
const deleteItem = () => {
Servis.remove(theItem.id)
.then(() => {
props.refreshList();
})
.catch((e) => {
console.log(e);
});
};
const validate = () => {
let imeError = "";
let kontaktError = "";
if (!theItem.ime) {
imeError = "obavezan unos imena!";
}
if (!theItem.kontakt) {
imeError = "obavezan unos kontakta!";
}
if (kontaktError || imeError) {
this.setState({ kontaktError, imeError });
return false;
}
return true;
};
return (
<div className="container">
{theItem ? (
<div className="edit-form">
<h4>Kontakt</h4>
<form>
<div className="form-group">
<label htmlFor="ime">Ime</label>
<input
type="text"
className="form-control"
// id="title"
name="ime"
value={theItem.Ime}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label htmlFor="Prezime">Prezime</label>
<input
type="text"
className="form-control"
// id="description"
name="Prezime"
value={theItem.Prezime}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label htmlFor="Datum">Datum</label>
<input
type="text"
className="form-control"
// id="description"
name="Datum"
value={theItem.Datum}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label htmlFor="Kontakt">Kontakt</label>
<input
type="text"
className="form-control"
// id="description"
name="Kontakt"
value={theItem.Kontakt}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label>
<strong>Status:</strong>
</label>
{theItem.published ? "Published" : "Pending"}
</div>
</form>
{theItem.published ? (
<button onClick={() => updatePublished(false)}>UnPublish</button>
) : (
<button onClick={() => updatePublished(true)}>Publish</button>
)}
<button onClick={deleteItem}>Delete</button>
<button type="submit" onClick={updateItem}>
Update
</button>
<p>{message}</p>
</div>
) : (
<div>
<br />
<p>Please click on a Tutorial...</p>
</div>
)}{" "}
</div>
);
}
The component passing the props:
import React, { useState, useEffect } from "react";
import firebase from "./firebase";
import { Link } from "react-router-dom";
export default function FireDetail({ match }) {
console.log(match);
console.log(match.params.id);
const [item, setItem] = useState([]);
const [loading, setLoading] = useState();
const getIt = () => {
setLoading(true);
const docRef = firebase
.firestore()
.collection("polja")
.doc(match.params.id)
.get()
.then((doc) => {
setItem(doc.data());
});
//
console.log(docRef);
//
// const docRef = firebase.firestore().collection("polja").doc("documentId")
//
setLoading(false);
};
useEffect(() => {
getIt();
}, [match]);
if (loading) {
return <h3>samo malo...</h3>;
}
return (
<div className="container">
<div>
{console.log("item: ", item)}
Kontakt: tip - email
<p> {item.Kontakt}</p>
</div>
<div>
<p>Datum rodjenja: {item.Datum}</p>
{item.Prezime} {item.Ime}
</div>
<Link to={`/kontakt/update/${item.id}`}> ajd </Link>
</div>
);
}
Or you might have an alternative idea on how to solve the problem?
indeed it is
export default function ContactUpdate(props) {
const initialState = {
ime: props.item.Ime,
prezime: props.item.Prezime,
datum: props.item.Datum,
kontakt: props.item.Kontakt,
id: props.Id,
};
const [theItem, setTheItem] = useState();
const [message, setMessage] = useState();
useEffect(() => {
setTheItem(props.item);
}, []);
const handleInputChange = (event) => {
const { name, value } = event.target;
setTheItem({ ...theItem, [name]: value });
console.log(theItem);
};
const updateItem = (theItem) => {
let data = {
Ime: theItem.Ime,
Prezime: theItem.Prezime,
Kontakt: theItem.Kontakt,
Datum: theItem.Datum,
};
console.log(updateItem());
Servis.update(theItem.id, data)
.then(() => {
setMessage("Uspjesno ste izmijenili unos!");
})
.catch((e) => {
console.log(e);
});
};
const deleteItem = () => {
Servis.remove(theItem.id).catch((e) => {
console.log(e);
});
};
return (
<div className="container">
{console.log(("theItem", props, theItem))}
{theItem ? (
<div className="edit-form">
<h4>Kontakt</h4>
<form>
<div className="form-group">
<label htmlFor="ime">Ime</label>
<input
type="text"
className="form-control"
name="Ime"
value={theItem.Ime}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label htmlFor="prezime">Prezime</label>
<input
type="text"
className="form-control"
name="Prezime"
value={theItem.Prezime}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label htmlFor="datum">Datum</label>
<input
type="text"
className="form-control"
name="Datum"
value={theItem.Datum}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label htmlFor="kontakt">Kontakt</label>
<input
type="text"
className="form-control"
name="Kontakt"
value={theItem.Kontakt}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label>
<strong>Status:</strong>
</label>
</div>
</form>
<button onClick={deleteItem}>Delete</button>
<button type="submit" onClick={updateItem}>
Update
</button>
<p>{message}</p>
</div>
) : (
<div>
<br />
<p>Odaberi jedan broj...</p>
</div>
)}{" "}
</div>
);
}

React: Why sign up form is not creating new user in firebase users?

Here I'm trying to build a signup form using the react-hook form. I'm trying to build a restaurant website for my own purpose. But I have tried many times. But I'm getting many errors. First of all when I sign up a new user then firebase is not creating a new user. The form is not validating completely. But I can't find out the problem. Where is the problem? Can anyone help, please?
Here is my signUp.js file
import React, { useEffect, useState } from 'react';
import { useAuth } from './useAuth'
import { useForm } from 'react-hook-form';
import logo from '../../Images/logo2.png';
import './SignUp.css'
const SignUp = () => {
const [returningUser, setReturningUser] = useState(false);
const {register, handleSubmit, watch, errors} = useForm();
const auth = useAuth();
const onSubmit = data => {
if(returningUser){
if(data.email && data.password){
auth.signIn(data.email, data.password)
}
}
else{
if(data.name && data.email && data.password){
auth.signUp(data.email, data.password, data.name)
}
}
}
return (
<div className="sign-up">
<div className="container">
<div className="logo-container ">
<img src={logo} alt=""/>
</div>
{
returningUser ?
<form onSubmit={handleSubmit(onSubmit) } action="" className="py-5">
{
auth && auth.user != null && <p className="text-danger">{auth.user.error}</p>
}
<div className="form-group">
<input name="email" className="form-control" {...register('email', {requried: true})} placeholder="Email"/>
{errors && errors.email && <span className="error">Email is Required</span>}
</div>
<div className="form-group">
<input type="password" name="password" className="form-control" {...register('password', {requried: true})} placeholder="password"/>
{errors&& errors.password && <span className="error">Password is Required</span>}
</div>
<div className="form-group">
<button className="btn btn-danger">Sign In</button>
</div>
<div className="option text-center">
<label onClick={() => setReturningUser(false)}>Create a new Account</label>
</div>
</form>
:
<form action="" onSubmit={handleSubmit(onSubmit)}>
<div className="form-group">
<input type="text" name="name" className="form-control"
{...register('name', {requried: true})} placeholder="Name"/>
{errors && errors.name && <span className="error">Name is Required</span>}
</div>
<div className="form-group">
<input type="email" name="email" className="form-control" {...register('email', {required: true})} placeholder="Email"/>
{errors && errors.email && <span className="error">Email is required</span>}
</div>
<div className="form-group">
<input type="password" name="password" className="form-control" {...register('password', {requried: true})} placeholder="Password"/>
{errors && errors.password && <span className="error">Password is Required</span>}
</div>
<div className="form-group">
<button className="btn btn-danger" type="submit">Sign Up</button>
</div>
<div className="option text-center">
<label onClick={() => setReturningUser(true)}>Already have an account!</label>
</div>
</form>
}
</div>
</div>
);
};
export default SignUp;
Here is my useAuth.js file
// import { faWindowRestore } from '#fortawesome/free-solid-svg-icons';
import firebase from "firebase/app";
import "firebase/auth";
import firebaseConfig from "../../firebase.config";
import { createContext, useContext, useEffect, useState } from "react";
import { Redirect, Route } from "react-router";
firebase.initializeApp(firebaseConfig);
const AuthContext = createContext();
export const AuthProvider = (props) => {
const auth = Auth();
return (
<AuthContext.Provider value={auth}>{props.children}</AuthContext.Provider>
);
};
export const useAuth = () => {
useContext(AuthContext);
};
export const PrivateRoute = ({ children, ...rest }) => {
let auth = useAuth();
return (
<Route
{...rest}
render={({ location }) =>
auth.user ? (
children
) : (
<Redirect
to={{
pathname: "/login",
state: { from: location },
}}
/>
)
}
/>
);
};
const Auth = () => {
const [user, setUser] = useState(null);
useEffect(() => {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
const currentUser = user;
setUser(currentUser);
// ...
} else {
// User is signed out
// ...
}
});
}, []);
const signIn = (email, password) => {
return firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then((res) => {
// Signed in
setUser(res.user);
window.history.back();
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
});
};
const signUp = (email, password, name) => {
return firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((res) => {
// firebase
// .auth()
// .currentUser.updateProfile({
// displayName: name,
// })
// .then(() => {
setUser(res.user);
window.history.back();
})
// Signed in
// ...
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ..
});
};
const signOut = () => {
return firebase
.auth()
.signOut()
.then((res) => {
// Sign-out successful.
setUser(null);
})
.catch((error) => {
// An error happened.
});
};
return {
user,
signIn,
signUp,
signOut,
};
};
export default Auth;

React limits the number of renders to prevent an infinite loop

I am making an application and I have an error that I do not understand very well. Apparently, it is in the hook that I am using to make protected pages. I share the error and the code below.
Unhandled Runtime Error Error: Too many re-renders. React limits the
number of renders to prevent an infinite loop.
import firebase from "firebase";
const firebaseConfig = {
apiKey: "Key",
authDomain: "Domain",
databaseURL: "URL",
projectId: "Id",
storageBucket: "Bucket",
messagingSenderId: "SenderId",
appId: "appId",
measurementId: "measurementId",
};
// Initialize Firebase
!firebase.apps.length && firebase.initializeApp(firebaseConfig);
export const database = firebase.database().ref();
const mapUserFromFirebaseAuthToUser = (user) => {
const { displayName, email, uid } = user;
return {
userName: displayName,
email,
uid,
};
};
export const onAuthStateChanged = (onChange) => {
const emailProvider = new firebase.auth();
return emailProvider.onAuthStateChanged((user) => {
const normalizedUser = user ? mapUserFromFirebaseAuthToUser(user) : null;
onChange(normalizedUser);
});
};
export const loginUser = ({ email, password }) => {
const emailProvider = new firebase.auth();
return emailProvider.signInWithEmailAndPassword(email, password);
};
export const singUp = () => {
const emailProvider = new firebase.auth();
return emailProvider.signOut();
};
the page where the application breaks
import { useState, useEffect } from "react";
import styles from "styles/Countries.module.css";
import useUser, { USER_STATES } from "hooks/useUser";
import NavbarMenu from "components/navBar";
import Footer from "components/footer";
import { database } from "utils/firebase";
import {
Table,
Button,
Container,
Modal,
ModalBody,
ModalHeader,
ModalFooter,
FormGroup,
} from "reactstrap";
export default function Countries() {
const user = useUser();
const [timeLine, setTimeLine] = useState([]);
const [isOpenModalAdd, setIsOpenModalAdd] = useState(false);
const [isOpenModalEdit, setIsOpenModalEdit] = useState(false);
const [name, setName] = useState("");
const [currency, setCurrency] = useState("");
const [base, setBase] = useState("");
const [km, setKm] = useState("");
const [minute, setMinute] = useState("");
const [code, setCode] = useState("");
const [country, setCountry] = useState({
name: "",
currency_code: "",
base_fare: "",
per_km: "",
per_minute: "",
});
useEffect(() => {
database.child("Admin/Country").on("value", (snapshot) => {
setTimeLine(snapshot.val());
});
}, []);
const selectCountry = (data, id, status) => {
setCountry(data);
setCode(id);
status === "edit" && setIsOpenModalEdit(true);
};
const editCountry = () => {
database.child("Admin/Country/" + code).set(country);
resetModalAdd();
setIsOpenModalEdit(false);
};
const saveCountry = () => {
const MapCountry = {
name: name,
currency_code: currency,
base_fare: base,
per_km: km,
per_minute: minute,
};
database.child("Admin/Country/" + code).set(MapCountry);
resetModalAdd();
setIsOpenModalAdd(false);
};
const resetModalAdd = () => {
setName("");
setCurrency("");
setBase("");
setKm("");
setMinute("");
setCode("");
};
const openModalAdd = () => {
setIsOpenModalAdd(true);
};
const closeModalAdd = () => {
setIsOpenModalAdd(false);
};
const handleChangeName = (event) => {
const { value } = event.target;
setName(value);
let string = value;
let part = string.split("");
if (part.length === 2) {
let code = part[0].toUpperCase() + part[1].toUpperCase();
setCode(code);
}
};
const handleChangeData = (event) => {
const { value } = event.target;
setCountry(value);
};
const handleChangeCurrency = (event) => {
const { value } = event.target;
setCurrency(value);
};
const handleChangeBase = (event) => {
const { value } = event.target;
setBase(value);
};
const handleChangeKm = (event) => {
const { value } = event.target;
setKm(value);
};
const handleChangeMinute = (event) => {
const { value } = event.target;
setMinute(value);
};
return user ? (
<>
<div className={styles.container}>
<div className={styles.principalMenu}>
<NavbarMenu>
<div className={styles.titleHeader}>
<div className={styles.title}>Administration System</div>
<div className={styles.subtitle}>User: {user.userName}</div>
</div>
</NavbarMenu>
</div>
<div>
<h3>Country</h3>
</div>
<Container>
<Button color="primary" onClick={openModalAdd}>
New Country
</Button>
<Table>
<thead>
<tr>
<th>Name</th>
<th>Currency Code</th>
<th>Base Fare</th>
<th>Per Km</th>
<th>Per Minute</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{Object.keys(timeLine).map((i) => {
return (
<tr key={i}>
<td>{timeLine[i].name}</td>
<td>{timeLine[i].currency_code}</td>
<td>{timeLine[i].base_fare}</td>
<td>{timeLine[i].per_km}</td>
<td>{timeLine[i].per_minute}</td>
<td>
<Button
color="primary"
onClick={selectCountry(timeLine[i], i, "edit")}
>
Editar
</Button>
{" "}
<Button color="danger">Eliminar</Button>
</td>
</tr>
);
})}
</tbody>
</Table>
<Modal isOpen={isOpenModalAdd}>
<ModalHeader>Insertar Registro</ModalHeader>
<ModalBody>
<div className="form-group">
<label>Name: </label>
<br />
<input
type="text"
className="form-control"
value={name}
onChange={handleChangeName}
/>
<label>Currency Code: </label>
<br />
<input
type="text"
className="form-control"
value={currency}
onChange={handleChangeCurrency}
/>
<label>Base Fare: </label>
<br />
<input
type="text"
className="form-control"
value={base}
onChange={handleChangeBase}
/>
<label>Per Km: </label>
<br />
<input
type="text"
className="form-control"
value={km}
onChange={handleChangeKm}
/>
<label>Per Minute: </label>
<br />
<input
type="text"
className="form-control"
value={minute}
onChange={handleChangeMinute}
/>
</div>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={saveCountry}>
Guardar
</Button>
{" "}
<Button color="danger" onClick={closeModalAdd}>
Cancelar
</Button>
</ModalFooter>
</Modal>
<Modal isOpen={isOpenModalEdit}>
<ModalHeader>Editar Registro</ModalHeader>
<ModalBody>
<div className="form-group">
<label>Name: </label>
<br />
<input
type="text"
className="form-control"
name="name"
value={country.name}
onChange={handleChangeData}
/>
<label>Currency Code: </label>
<br />
<input
type="text"
className="form-control"
name="currency_code"
value={country.currency_code}
onChange={handleChangeData}
/>
<label>Base Fare: </label>
<br />
<input
type="text"
className="form-control"
name="base_fare"
value={country.base_fare}
onChange={handleChangeData}
/>
<label>Per Km: </label>
<br />
<input
type="text"
className="form-control"
name="per_km"
value={country.per_km}
onChange={handleChangeData}
/>
<label>Per Minute: </label>
<br />
<input
type="text"
className="form-control"
name="per_minute"
value={country.per_minute}
onChange={handleChangeData}
/>
</div>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={editCountry}>
Guardar
</Button>
{" "}
<Button color="danger" onClick={setIsOpenModalEdit(false)}>
Cancelar
</Button>
</ModalFooter>
</Modal>
</Container>
<Footer />
</div>
</>
) : user === USER_STATES.NOT_KNOWN ? (
<>
<div className={styles.container}>
<h1>Loading...</h1>
</div>
</>
) : (
<>
<div className={styles.container}>
<h1>Not authorized</h1>
</div>
</>
);
}
The hooks used for protected pages:
import { Router } from "next/router";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { onAuthStateChanged } from "utils/firebase";
export const USER_STATES = {
NOT_LOGGED: null,
NOT_KNOWN: undefined,
};
export default function useUser() {
const [user, setUser] = useState(USER_STATES.NOT_KNOWN);
const router = useRouter();
useEffect(() => {
onAuthStateChanged(setUser);
}, []);
useEffect(() => {
user === USER_STATES.NOT_LOGGED && router.push("/login");
}, [user]);
return user;
}
I hope this is enough to give me a hand. I have already tried to solve but the truth is I do not find the problem.
The logic in these lines is not correct:
useEffect(() => {
onAuthStateChanged(setUser);
}, []);
useEffect(() => {
user === USER_STATES.NOT_LOGGED && router.push("/login");
}, [user]);
I understand the first useEffect is used to update the state,
but the second useEffect watches this state and returning boolean?
Instead of user === USER_STATES.NOT_LOGGED && router.push("/login");, it should be:
if (USER_STATES.NOT_LOGGED) { router.push("/login"); }

Resources