Skip to content

Commit

Permalink
feat: added custom validation hooks (#877)
Browse files Browse the repository at this point in the history
  • Loading branch information
tamalCodes committed Jun 22, 2023
1 parent cb74c97 commit 87c303b
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 130 deletions.
8 changes: 5 additions & 3 deletions server/routes/user/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ router.post("/register", async (req, res) => {
const existingUser = await User.findOne({ email });

if (existingUser) {
return res.status(409).json({ message: "User already exists" });
return res
.status(409)
.json({ message: "User already exists, please login." });
}

const hashedPassword = await bcrypt.hash(data.password, 10);
Expand All @@ -25,7 +27,7 @@ router.post("/register", async (req, res) => {
password: hashedPassword,
});
await newUser.save();
res.status(201).json({ message: "Registration successful, please login" });
res.status(201).json({ message: "Signed you up, please login." });
} catch (e) {
res.status(500).json({ message: "Internal Server Error" });
}
Expand Down Expand Up @@ -102,7 +104,7 @@ router.post("/login", async (req, res) => {

jwt.sign(payload, process.env.JWT_SECRET, (err, token) => {
if (err) throw new Error("Something Went Wrong!");
res.status(201).json({ token, isuser: true });
res.status(201).json({ token, isuser: true, message: "Logged you in !" });
});
} catch (err) {
res.status(500).json({ message: "Internal Server Error" });
Expand Down
2 changes: 1 addition & 1 deletion server/schema/club/ClubSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const ClubsSchema = mongoose.Schema({
required: true,
},
pincode: {
type: Number,
type: String,
required: true,
},
tagLine: {
Expand Down
2 changes: 1 addition & 1 deletion server/schema/user/UserSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const UserSchema = mongoose.Schema({
required: false,
},
pincode: {
type: Number,
type: String,
required: false,
},
});
Expand Down
102 changes: 102 additions & 0 deletions src/hooks/useValidation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
const useValidation = (credentials, userSignup, clubSignup) => {
const errors = [];
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const nameRegex = /^[a-zA-Z]+$/;

if (!credentials.email) {
errors.push({ error: true, message: "Please enter your email" });
} else if (!emailRegex.test(credentials.email)) {
errors.push({ error: true, message: "Please enter a valid email" });
}

if (!credentials.password) {
errors.push({ error: true, message: "Please enter your password" });
} else if (credentials.password.length < 6) {
errors.push({
error: true,
message: "Password must be at least 6 characters long",
});
}

if (userSignup) {
if (!credentials.firstname) {
errors.push({ error: true, message: "Please enter your first name" });
} else if (!nameRegex.test(credentials.firstname)) {
errors.push({ error: true, message: "Please enter a valid first name" });
} else if (
credentials.firstname.length < 3 ||
credentials.firstname.length > 30
) {
errors.push({
error: true,
message: "First name must be between 3 and 30 characters long",
});
}

if (!credentials.lastname) {
errors.push({ error: true, message: "Please enter your last name" });
} else if (!nameRegex.test(credentials.lastname)) {
errors.push({ error: true, message: "Please enter a valid last name" });
} else if (
credentials.lastname.length < 3 ||
credentials.lastname.length > 30
) {
errors.push({
error: true,
message: "Last name must be between 3 and 30 characters long",
});
}
}

if (clubSignup) {
if (!credentials.name) {
errors.push({ error: true, message: "Please enter your club name" });
} else if (!nameRegex.test(credentials.name)) {
errors.push({ error: true, message: "Please enter a valid club name" });
} else if (credentials.name.length < 3 || credentials.name.length > 30) {
errors.push({
error: true,
message: "Club name must be between 3 and 30 characters long",
});
}

if (!credentials.tagLine) {
errors.push({ error: true, message: "Please enter your club tagline" });
} else if (!nameRegex.test(credentials.tagLine)) {
errors.push({
error: true,
message: "Please enter a valid club tagline",
});
} else if (
credentials.tagLine.length < 3 ||
credentials.tagLine.length > 100
) {
errors.push({
error: true,
message: "Club tagline must be between 3 and 100 characters long",
});
}
}

if (userSignup || clubSignup) {
if (!credentials.address) {
errors.push({ error: true, message: "Please enter your address" });
} else if (
credentials.address.length < 20 ||
credentials.address.length > 200
) {
errors.push({
error: true,
message: "Address must be between 20 and 200 characters long",
});
}

if (!credentials.pincode) {
errors.push({ error: true, message: "Please enter your pincode" });
}
}

return errors.length ? errors : { error: false, message: "" };
};

export default useValidation;
78 changes: 24 additions & 54 deletions src/pages/user/UserLogin.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ import { Link, useNavigate } from "react-router-dom";
import "../../styles/UserLogin.css";
import { LoginUser } from "../../service/MilanApi";
import Cookies from "js-cookie";
import { toast } from "react-toastify";

import SchemaValidator, { msgLocalise } from "../../utils/validation";
import "react-toastify/dist/ReactToastify.css";
import { Helmet } from "react-helmet-async";
import { ReactComponent as AuthBanner } from "../../assets/pictures/authpages/authbannerimg.svg";
import { showErrorToast, showSuccessToast } from "../../utils/showToast";
import Button from "../../components/Button";
import { FiEye, FiEyeOff } from "react-icons/fi";
import useValidation from "../../hooks/useValidation";

function UserLogin() {
const Navigate = useNavigate();
const [passwordType, setPasswordType] = useState("password");
const [credentials, setCredentials] = useState({
email: "",
password: "",
});

function Anchor(props) {
return (
Expand All @@ -27,65 +29,36 @@ function UserLogin() {
);
}

const [credentials, setCredentials] = useState({
email: "",
password: "",
});

const FormDataProto = {
id: "/LoginForm",
type: "object",
properties: {
email: { type: "string", format: "email" },
password: { type: "string", minLength: 4 },
},
required: ["email", "password"],
};

//* To set the value as soon as we input
const handleChange = (e) => {
setCredentials({ ...credentials, [e.target.name]: e.target.value });
};

//* Submit to backend
//* If alright we get a cookie with token
const callUserLoginAPI = async () => {
const Data = await LoginUser(credentials);

if (Data?.status === 201) {
Cookies.set("token", Data?.data?.token);
showSuccessToast(Data?.data?.message);
Navigate("/");
} else {
showErrorToast(Data?.data?.message);
setCredentials({ email: "", password: "" });
}
};

const handleSubmit = (e) => {
toast.clearWaitingQueue();
e.preventDefault();
var validator = SchemaValidator(FormDataProto, { ...credentials });

if (validator.valid) {
const Data = LoginUser(credentials);

Data.then((response) => {
if (response?.data.token) {
Cookies.set("token", response.data.token);
showSuccessToast("Logged you in !");
Navigate("/");
} else {
setCredentials({ email: "", password: "" });
}
}).catch(() => {
showErrorToast("Server error, try again later !");
const validationErrors = useValidation(credentials);
if (validationErrors.length > 0) {
validationErrors.forEach((error) => {
showErrorToast(error.message);
});
} else {
validator.errors.map(function (e) {
return toast(`${e.path[0]} : ${msgLocalise(e)}`, {
position: "top-right",
autoClose: 1000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
closeButton: false,
});
});
callUserLoginAPI();
}
};

const [passwordType, setPasswordType] = useState("password");

const passwordToggle = () => {
if (passwordType === "password") {
setPasswordType("text");
Expand Down Expand Up @@ -163,9 +136,6 @@ function UserLogin() {
</div>
</div>

{/* RememberMe Tab */}

{/* Login Button */}
<div className="btn-container btn-container-desktop">
<Button type="submit" className="login-btn">
Login
Expand Down
Loading

0 comments on commit 87c303b

Please sign in to comment.