I’m trying to let the user sign in using email OR username, I already implemented the backend and it’s working fine using Postman, but I didn’t know how to implement it in the frontend,
Login.jsx:
export default function Login() { const [credentials, setCredentials] = useState({ email: undefined, username: undefined, password: undefined, }); const [loginErr, setMsg] = useState({ fail: false, msg: "", }); const { user, isFetching, dispatch } = useContext(Context); const handleChange = (e) => { setCredentials((prev) => ({ ...prev, [e.target.id]: e.target.value })); }; const handleSubmit = async (e) => { e.preventDefault(); dispatch({ type: "LOGIN_START" }); try { const res = await axios.post("/login", credentials); dispatch({ type: "LOGIN_SUCCESS", payload: res.data }); } catch (err) { setMsg({ fail: true, msg: err.response.data.message }); dispatch({ type: "LOGIN_FAILURE", payload: err.response.data }); } }; return ( <div className="login"> {/* LOGIN FORM */} <form onSubmit={handleSubmit}> <Stack> <Typography> Login to </Typography> {/* Username or Email Address */} <Typography variant="h9" gutterBottom component="div" style={{ fontWeight: "bold", textAlign: "left"}} mt={1}> Username or Email Address </Typography> <div class="relative w-full"> <div class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none"> <PersonIcon class="w-5 h-5" /> </div> <input type="text" className="loginInput" style={{ border: loginErr.fail ? '1px solid red' : '' }} // ref={userRef} name="email" id="email" onChange={handleChange}/> </div> <button className="loginButton" type="submit" disabled={isFetching}> {isFetching ? ( <CircularProgress size={15}/> ) : ( <Typography variant="subtitle2" color="white"> Login </Typography>)} </button> </Stack> </form> {/* LOGIN FORM ENDS */} </div> ); }
My question is how to let the INPUT knows if the user is typing a username or an email and then act accordingly, or is there any easy way to get this done?
Backend Auth.js:
router.post("/login", async (req, res, next) => { try { if (!req.body.password) { return next(createError(400, "Invalid password")); } const user = await User.findOne({$or: [ {email: req.body.email}, {username: req.body.username} ]}); if (!user) return next(createError(404, "User not found!")); const isPasswordCorrect = await bcrypt.compare( req.body.password, user.password ); if (!isPasswordCorrect) return next(createError(400, "Wrong password!")); const { password, ...others } = user._doc; res.status(200).json(others); } catch (err) { next(err); } });
Advertisement
Answer
So i implemented it on the back-end, I figured out that I don’t have to check if the input is username or an email all I have to do is using $or in the User.findOne it worked like charm here is the code in case of somebody finds it helpful
const user = await User.findOne({$or: [ {email: req.body.emailOrUsername}, {username: req.body.emailOrUsername} ]});
and in the front-end:
const [credentials, setCredentials] = useState({ emailOrUsername: undefined, password: undefined, });
and for the input:
{/* Username or Email Address */} <Typography variant="h9" gutterBottom component="div" style={{ fontWeight: "bold", textAlign: "left"}} mt={1}> Username or Email Address </Typography> <div class="relative w-full"> <div class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none"> <PersonIcon class="w-5 h-5" /> </div> <input type="text" className="loginInput" style={{ border: loginErr.fail ? '1px solid red' : '' }} // ref={userRef} name="emailOrUsername" id="emailOrUsername" onChange={handleChange}/> </div>