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:
JavaScript
x
95
95
1
export default function Login() {
2
3
const [credentials, setCredentials] = useState({
4
email: undefined,
5
username: undefined,
6
password: undefined,
7
});
8
9
const [loginErr, setMsg] = useState({
10
fail: false,
11
msg: "",
12
13
});
14
15
const { user, isFetching, dispatch } = useContext(Context);
16
17
const handleChange = (e) => {
18
setCredentials((prev) => ({ prev, [e.target.id]: e.target.value }));
19
};
20
21
const handleSubmit = async (e) => {
22
e.preventDefault();
23
dispatch({ type: "LOGIN_START" });
24
try {
25
const res = await axios.post("/login", credentials);
26
dispatch({ type: "LOGIN_SUCCESS", payload: res.data });
27
} catch (err) {
28
setMsg({ fail: true, msg: err.response.data.message });
29
dispatch({ type: "LOGIN_FAILURE", payload: err.response.data });
30
}
31
};
32
33
34
return (
35
36
<div className="login">
37
38
{/* LOGIN FORM */}
39
<form onSubmit={handleSubmit}>
40
<Stack>
41
42
<Typography>
43
Login to
44
</Typography>
45
46
{/* Username or Email Address */}
47
<Typography variant="h9"
48
gutterBottom
49
component="div"
50
style={{ fontWeight: "bold",
51
textAlign: "left"}}
52
mt={1}>
53
Username or Email Address
54
</Typography>
55
56
<div class="relative w-full">
57
<div class="flex absolute
58
inset-y-0 left-0 items-center pl-3
59
pointer-events-none">
60
<PersonIcon class="w-5 h-5" />
61
</div>
62
<input type="text"
63
className="loginInput"
64
style={{ border: loginErr.fail ? '1px solid red' : '' }}
65
// ref={userRef}
66
name="email"
67
id="email"
68
onChange={handleChange}/>
69
</div>
70
71
<button
72
className="loginButton"
73
type="submit"
74
disabled={isFetching}>
75
76
{isFetching ? (
77
<CircularProgress size={15}/>
78
) : (
79
<Typography
80
variant="subtitle2"
81
color="white">
82
Login
83
</Typography>)}
84
</button>
85
86
</Stack>
87
</form>
88
89
{/* LOGIN FORM ENDS */}
90
91
</div>
92
);
93
94
}
95
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:
JavaScript
1
29
29
1
router.post("/login", async (req, res, next) => {
2
3
try {
4
5
if (!req.body.password) {
6
return next(createError(400, "Invalid password"));
7
}
8
9
const user = await User.findOne({$or: [
10
{email: req.body.email},
11
{username: req.body.username}
12
]});
13
if (!user) return next(createError(404, "User not found!"));
14
15
const isPasswordCorrect = await bcrypt.compare(
16
req.body.password,
17
user.password
18
);
19
if (!isPasswordCorrect) return next(createError(400, "Wrong password!"));
20
21
const { password, others } = user._doc;
22
23
res.status(200).json(others);
24
} catch (err) {
25
next(err);
26
}
27
28
});
29
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
JavaScript
1
5
1
const user = await User.findOne({$or: [
2
{email: req.body.emailOrUsername},
3
{username: req.body.emailOrUsername}
4
]});
5
and in the front-end:
JavaScript
1
5
1
const [credentials, setCredentials] = useState({
2
emailOrUsername: undefined,
3
password: undefined,
4
});
5
and for the input:
JavaScript
1
25
25
1
{/* Username or Email Address */}
2
<Typography variant="h9"
3
gutterBottom
4
component="div"
5
style={{ fontWeight: "bold",
6
textAlign: "left"}}
7
mt={1}>
8
Username or Email Address
9
</Typography>
10
11
<div class="relative w-full">
12
<div class="flex absolute
13
inset-y-0 left-0 items-center pl-3
14
pointer-events-none">
15
<PersonIcon class="w-5 h-5" />
16
</div>
17
<input type="text"
18
className="loginInput"
19
style={{ border: loginErr.fail ? '1px solid red' : '' }}
20
// ref={userRef}
21
name="emailOrUsername"
22
id="emailOrUsername"
23
onChange={handleChange}/>
24
</div>
25