'How can I show error message when wrong password or username?

How can I show an error message if the username or password input is not the same on MongoDB? I don't know if my approach is right and I have been having trouble fixing this.

How can I show to the UI if the loginFailure() dispatch function kicks in? How can I render it to the UI telling the user if it works or not.

like warning error of

wrong username or password

login.jsx

import React, { useState } from 'react'
import { useDispatch } from 'react-redux'
import { useHistory } from 'react-router-dom'
import { login } from '../../redux/apiCalls'
import './login.css'

const Login = () => {
    const [username, setUsername ] = useState("")
    const [password, setPassword ] = useState("")
    const history = useHistory()
    const dispatch = useDispatch()
    
    const handleClick =(e) =>{
        e.preventDefault()
           if(login(dispatch,{username,password})){
             setTimeout(function(){
                 window.location.reload();
                 },500);
                console.log("Hello")
     
           }
           else{
               console.log("Erorr")
           }
    }


    return (
        <div className="login">
            <input type="text" placeholder="username" onChange={e=>setUsername(e.target.value)} />
            <input type="password" placeholder="password" onChange={e=>setPassword(e.target.value)} />
            <button onClick={handleClick}>submit</button>
        </div>
    )
}

export default Login

userRedux.js

export const userSlice = createSlice({
  name: 'user',
  initialState: {
    currentUser: null,
    isFetching: false,
    error: false,
  },
  reducers: {
    loginStart: (state) => {
      state.isFetching = true
    },
    loginSuccess: (state, action) => {
      state.isFetching = false
      state.currentUser = action.payload
    },
    loginFailure: (state) => {
      state.isFetching = false
      state.error = true
    },
    logout: (state) => {
      state.currentUser = false
    },
  },
})
export const { loginStart, loginSuccess, loginFailure, logout } =
  userSlice.actions
export default userSlice.reducer

apicalls.js

export const login = async (dispatch, user) => {
  dispatch(loginStart())
  try {
    const res = await publicRequest.post('/auth/login', user)
    dispatch(loginSuccess(res.data))
  } catch (error) {
    dispatch(loginFailure())
   window.alert('Wrong password or Username')
  }
}

Using windows.alert("wrong pass or username"), it's working but is it possible that I can render a Ui for this? instead of popup boxes?

loginAuth.js

router.post('/login', async (req, res) => {
  try {
    const user = await User.findOne({ username: req.body.username })
    !user && res.status(401).json('Wrong username')

    const hashedPassword = CryptoJS.RC4.decrypt(
      user.password,

      process.env.SECRET_KEY
    )
    const OriginalPassword = hashedPassword.toString(CryptoJS.enc.Utf8)
    OriginalPassword !== req.body.password &&
      res.status(401).json('Wrong password')

    const accessToken = jwt.sign(
      {
        id: user.id,
        isAdmin: user.isAdmin,
      },
      process.env.JWT_SEC,
      { expiresIn: '3d' }
    )

    const { password, ...others } = user._doc

    res.status(200).json({ ...others, accessToken })
  } catch (error) {
    res.status(500).json(error)
  }
})


Solution 1:[1]

A simple solution would be to set a piece of state like;

const [loginErr, setLoginErr] = useState(false);

Then, when your login function returns false you can do;

    const handleClick =(e) =>{
        e.preventDefault()
           if(login(dispatch,{username,password})){
             setTimeout(function(){
                 window.location.reload();
                 },500);
                console.log("Hello")
     
           }
           else{
               setLoginErr(true);
           }
    }

Then, have a conditional render; this could be a component or just a div saying the error you with to display like;

<>
  { loginErr ? <SomeError /> : null }
</>

Solution 2:[2]

I had a similar solution like using setstate but login(dispatch,{username,password}) will always return some value so it will always execute the if block only. What you can do is if you are storing the user in local storage then

const handleClick =(e) =>{
    e.preventDefault()
       login(dispatch,{username,password})
       if(JSON.parse(JSON.parse(localStorage.getItem("user"))){
         setTimeout(function(){
             window.location.reload();
             },500);
            console.log("Hello")
 
       }
       else{
           setLoginErr(true);
       }
}

then you can use the conditional display like

{ loginErr && <p>Invalid credentials</p> }

or else if use context then you can

const {user} = useContext(AuthContext)
const handleClick =(e) =>{
e.preventDefault()
   login(dispatch,{username,password})
   if(user){
     setTimeout(function(){
         window.location.reload();
         },500);
        console.log("Hello")

   }
   else{
       setLoginErr(true);
   }

}

and use the same conditional rendering

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Robert L
Solution 2 piyushsakhare