diff --git a/client/src/components/ErrorMessage.jsx b/client/src/components/ErrorMessage.jsx
index 44210aa..38ab7f4 100644
--- a/client/src/components/ErrorMessage.jsx
+++ b/client/src/components/ErrorMessage.jsx
@@ -1,12 +1,16 @@
import React from "react";
-import { Alert } from "react-bootstrap";
-const ErrorMessage = ({ variant = "info", children }) => {
+const ErrorMessage = ({ errors, variant }) => {
+ if (!errors) {
+ return null;
+ }
return (
-
- {children}
-
+
+ {Object.values(errors).map((error) => (
+
{error}
+ ))}
+
);
};
-export default ErrorMessage;
\ No newline at end of file
+export default ErrorMessage;
diff --git a/client/src/hooks/useAuth.js b/client/src/hooks/useAuth.js
new file mode 100644
index 0000000..47d8146
--- /dev/null
+++ b/client/src/hooks/useAuth.js
@@ -0,0 +1,97 @@
+import { useEffect, useReducer } from "react";
+import axios from "axios";
+
+const useAuth = () => {
+ const [state, dispatch] = useReducer(
+ (state, action) => {
+ switch (action.type) {
+ case "reset":
+ return {
+ loading: false,
+ error: null,
+ user: null,
+ };
+ case "error":
+ return {
+ ...state,
+ loading: false,
+ error: action.error,
+ };
+ case "login":
+ case "register":
+ return {
+ ...state,
+ loading: true,
+ };
+ case "success":
+ return {
+ loading: false,
+ error: null,
+ user: action.user,
+ };
+ default:
+ return state;
+ }
+ },
+ {
+ loading: false,
+ error: null,
+ user: null,
+ }
+ );
+
+ const register = async (values) => {
+ dispatch({ type: "register" });
+ try {
+ const response = await axios.post("/api/users/register", values, {
+ baseURL: "http://localhost:5000",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ const { data } = response;
+ localStorage.setItem("userInfo", JSON.stringify(data));
+ dispatch({ type: "success", user: data });
+ } catch (error) {
+ dispatch({ type: "error", error: error.message });
+ }
+ };
+
+ const login = async (values) => {
+ dispatch({ type: "login" });
+ try {
+ const response = await axios.post("/api/users/login", values, {
+ baseURL: "http://localhost:5000",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ const { data } = response;
+ localStorage.setItem("userInfo", JSON.stringify(data));
+ dispatch({ type: "success", user: data });
+ } catch (error) {
+ dispatch({ type: "error", error: error.message });
+ }
+ };
+
+ const logout = () => {
+ localStorage.removeItem("userInfo");
+ dispatch({ type: "reset" });
+ };
+
+ useEffect(() => {
+ const user = JSON.parse(localStorage.getItem("userInfo"));
+ if (user) {
+ dispatch({ type: "success", user });
+ }
+ }, []);
+
+ return {
+ ...state,
+ register,
+ login,
+ logout,
+ };
+};
+
+export default useAuth;
diff --git a/client/src/hooks/useMakeRequest.js b/client/src/hooks/useMakeRequest.js
new file mode 100644
index 0000000..4ba0627
--- /dev/null
+++ b/client/src/hooks/useMakeRequest.js
@@ -0,0 +1,32 @@
+import { useState } from "react";
+import axios from "axios";
+
+const useMakeRequest = ({
+ requestMethod,
+ requestUrl,
+ requestData,
+ requestConfig,
+}) => {
+ const [response, setResponse] = useState(null);
+ const [error, setError] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ const makeRequest = async () => {
+ setLoading(true);
+ try {
+ const res = await axios[requestMethod](
+ requestUrl,
+ requestData,
+ requestConfig
+ );
+ setResponse(res);
+ } catch (err) {
+ setError(err);
+ }
+ setLoading(false);
+ };
+
+ return { makeRequest, response, error, loading };
+};
+
+export default useMakeRequest;
diff --git a/client/src/screens/LoginPage/LoginPage.jsx b/client/src/screens/LoginPage/LoginPage.jsx
index 9a5b990..4fab485 100644
--- a/client/src/screens/LoginPage/LoginPage.jsx
+++ b/client/src/screens/LoginPage/LoginPage.jsx
@@ -16,7 +16,7 @@ const LoginPage = () => {
});
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
-
+
const submitHandler = async (event) => {
event.preventDefault();
setLoading(true);
@@ -29,11 +29,12 @@ const LoginPage = () => {
});
localStorage.setItem("userInfo", JSON.stringify(response.data));
- console.log(values);
+ console.log(response.data);
setLoading(false);
resetForm();
} catch (err) {
- setError(err.message);
+ console.log(err);
+ setError(err.error);
setLoading(false);
}
};
@@ -42,7 +43,7 @@ const LoginPage = () => {
{loading &&
}
- {error &&
{error}
}
+ {error &&
{error}
}
Email address
diff --git a/client/src/screens/RegisterPage/RegisterPage.jsx b/client/src/screens/RegisterPage/RegisterPage.jsx
index 1133b6c..dfe6bdb 100644
--- a/client/src/screens/RegisterPage/RegisterPage.jsx
+++ b/client/src/screens/RegisterPage/RegisterPage.jsx
@@ -1,94 +1,104 @@
-import React,{useState,useEffect} from 'react'
-import './register.css'
-import MainScreen from './../../components/MainScreen';
-import { Form ,Button} from 'react-bootstrap';
-import axios from 'axios'
-import ErrorMessage from './../../components/ErrorMessage';
-import Loading from './../../components/Loading';
+import React, { useState } from "react";
+import "./register.css";
+import MainScreen from "./../../components/MainScreen";
+import { Form, Button } from "react-bootstrap";
+import ErrorMessage from "./../../components/ErrorMessage";
+import Loading from "./../../components/Loading";
+import useForm from "../../hooks/useForm";
+import axios from "axios";
+
const RegisterPage = () => {
- const [email, setEmail] = useState("");
- const [name, setName] = useState("");
- const [pic, setPic] = useState(
- "https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg"
- );
- const [password, setPassword] = useState("");
- const [confirmpassword, setConfirmPassword] = useState("");
- const [message, setMessage] = useState(null);
- const [picMessage, setPicMessage] = useState(null);
- const[error,setError] =useState(false)
- const[loading,setLoading] =useState(false)
- const submitHandler = async(e)=>{
- e.preventDefault()
- if(password !== confirmpassword){
- setMessage("passwords do not match")
- }else{
- setMessage(null)
- try{
- setLoading(true)
- const {data}= await axios.post("/api/users/",{name,pic,email,password}, {
- baseURL: "http://localhost:5000",
- headers: {
- "Content-Type": "application/json",
- }
- });
- setLoading(false)
+ const [values, handleChange, resetForm] = useForm({
+ email: "",
+ name: "",
+ pic: "https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg",
+ password: "",
+ confirmpassword: "",
+ });
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+
+ const submitHandler = async (event) => {
+ event.preventDefault();
+ setLoading(true);
+ try {
+ const response = await axios.post("/api/users/register", values, {
+ baseURL: "http://localhost:5000",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
- localStorage.setItem("userInfo", JSON.stringify(data))
- }
- catch(err){
- setError(error.response.data.message)
- }
- }
- console.log(email);
+ localStorage.setItem("userInfo", JSON.stringify(response.data));
+ console.log(values);
+ setLoading(false);
+ resetForm();
+ } catch (err) {
+ setError(err.message);
+ setLoading(false);
}
+ };
+
return (
-
- {error &&
{error}}
- {message &&
{message}}
- {loading &&
}
+
+
+ {loading && }
- Enter name
- setName(e.target.value)} />
-
+
+ Enter name
+
+
-
- Email address
- setEmail(e.target.value)} />
-
+
+ Email address
+
+
-
- Password
- setPassword(e.target.value)}/>
-
-
- confirm Password
- setConfirmPassword(e.target.value)} />
-
-
- upload profile picture
-
-
+
+ Password
+
+
+
+ confirm Password
+
+
+
+ upload profile picture
+
+
-
-
-
+
+
+
- )
-}
+ );
+};
-export default RegisterPage
\ No newline at end of file
+export default RegisterPage;
diff --git a/server/controllers/userControllers.js b/server/controllers/userControllers.js
index a72d0ea..f47fb4f 100644
--- a/server/controllers/userControllers.js
+++ b/server/controllers/userControllers.js
@@ -1,51 +1,69 @@
-const User = require('../models/userModel.js')
-const ascyncHandler = require('express-async-handler')
-const generateToken = require('../utill/generateToken')
-
-const registerUser = ascyncHandler(async(req,res)=>{
- const { name, email ,password,pic } = req.body;
- const userExist = await User.findOne({email});
- if(userExist){
- res.status(400)
- throw new Error("User already exists")
- }
- const user = await User.create({
- name,
- email,
- password,
- pic
+const User = require("../models/userModel.js");
+const asyncHandler = require("express-async-handler");
+const generateToken = require("../utill/generateToken");
+const encryptionUtil = require("../utill/encryptionUtil");
+const bcrypt = require("bcrypt");
+
+const registerUser = asyncHandler(async (req, res) => {
+ const { name, email, password, pic } = req.body;
+ const userExist = await User.findOne({ email });
+ if (userExist) {
+ return res.status(409).json({ message: "User already exists" });
+ }
+
+ const { salt, encryptedPassword } = await encryptionUtil.encryptPassword(
+ password
+ );
+
+ const user = new User({
+ name,
+ email,
+ password: encryptedPassword,
+ pic,
+ salt,
+ });
+ await user.save();
+
+ if (user) {
+ res.status(201).json({
+ _id: user._id,
+ name: user.name,
+ isAdmin: user.isAdmin,
+ pic: user.pic,
+ token: generateToken(user._id),
+ });
+ } else {
+ res.status(500).send({ error: "Error occured" });
+ }
+});
+
+const authUser = asyncHandler(async (req, res) => {
+ const { email, password } = req.body;
+ const user = await User.findOne({ email }, "_id name isAdmin pic").select(
+ "+password"
+ );
+
+ if (!user) {
+ return res.status(404).json({ error: "User not found" });
+ }
+
+ const isValidPassword = await encryptionUtil.comparePassword(
+ password,
+ user.salt,
+ user.password
+ );
+
+ if (!isValidPassword) {
+ res.json({
+ _id: user._id,
+ name: user.name,
+ isAdmin: user.isAdmin,
+ pic: user.pic,
+ token: generateToken(user._id),
});
+ } else {
+ res.status(401).send({ error: "Incorrect password" });
+ }
+});
- if(user){
- res.status(201).json({
- _id:user._id,
- name: user.name,
- isAdmin: user.isAdmin,
- pic:user.pic,
- token: generateToken(user._id)
- })
- }
- else{
- res.status(400)
- throw new Error ("Error occured")
- }
-})
-
-const authUser = ascyncHandler(async(req,res)=>{
- const { email ,password} = req.body;
- const user = await User.findOne({email})
- if(user && (await user.matchPassword(password))){
- res.json({
- _id:user._id,
- name: user.name,
- isAdmin: user.isAdmin,
- pic:user.pic,
- token: generateToken(user._id)
- })
- }
- else{
- res.status(400)
- throw new Error ("Invalid Email or password")
- }
-})
-module.exports ={ registerUser,authUser}
\ No newline at end of file
+module.exports = { registerUser, authUser };
diff --git a/server/index.js b/server/index.js
index 1a95be8..5c9d4d0 100644
--- a/server/index.js
+++ b/server/index.js
@@ -3,8 +3,7 @@ require("dotenv").config();
const notes = require("./data/noes.js");
const userRoutes = require("./routes/userRoutes");
const connectDB = require("./config/db");
-const { notFound, errorHandler } = require("./middlewares/errorMiddleWare");
-const cors= require('cors')
+const cors = require("cors");
const PORT = process.env.PORT || 5000;
const app = express();
@@ -13,16 +12,17 @@ connectDB();
// app.use(notFound , errorHandler)
app.use(express.json());
-app.use(cors({
- allowedHeaders: "*",
- allowedMethods:"*",
- origin:"*"
-}))
+app.use(
+ cors({
+ allowedHeaders: "*",
+ allowedMethods: "*",
+ origin: "*",
+ })
+);
app.get("/", (req, res) => {
res.send("Hello");
});
-
app.get("/api/notes", (req, res) => {
res.json(notes);
});
@@ -35,4 +35,4 @@ app.use("/api/users", userRoutes);
app.listen(PORT, () => {
console.log(`App is running on http://localhost:${PORT}`);
-});
\ No newline at end of file
+});
diff --git a/server/middlewares/errorMiddleWare.js b/server/middlewares/errorMiddleWare.js
index 48fe8fb..c0f1f28 100644
--- a/server/middlewares/errorMiddleWare.js
+++ b/server/middlewares/errorMiddleWare.js
@@ -1,16 +1,16 @@
const notFound = (req, res, next) => {
- const error = new Error(`Not Found - ${req.originalUrl}`);
- res.status(404);
- next(error);
- };
-
- const errorHandler = (err, req, res, next) => {
- const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
- res.status(statusCode);
- res.json({
- message: err.message,
- stack: process.env.NODE_ENV === "production" ? null : err.stack,
- });
- };
-
- module.exports = { notFound, errorHandler };
\ No newline at end of file
+ const error = new Error(`Not Found - ${req.originalUrl}`);
+ res.status(404);
+ next(error);
+};
+
+const errorHandler = (err, req, res, next) => {
+ const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
+ res.status(statusCode);
+ res.json({
+ message: err.message,
+ stack: process.env.NODE_ENV === "production" ? null : err.stack,
+ });
+};
+
+module.exports = { notFound, errorHandler };
diff --git a/server/models/userModel.js b/server/models/userModel.js
index 7c9686b..f9ce949 100644
--- a/server/models/userModel.js
+++ b/server/models/userModel.js
@@ -1,47 +1,37 @@
-const mongoose = require('mongoose')
-const bcrypt = require('bcrypt')
-const userSchema = mongoose.Schema({
-
- name:{
- type:String,
- required:true
- },
- email:{
- type:String,
- required:true,
- unique:true
- },
- password:{
- type:String,
- required:true
- },
- isAdmin:{
- type:Boolean,
- required:true,
- default:false
- },
- pic:{
- type:String,
- required:true,
- default: "https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg"
- },
-
-},{
- timestamps:true,
-})
+const mongoose = require("mongoose");
+const bcrypt = require("bcrypt");
+const userSchema = mongoose.Schema(
+ {
+ name: {
+ type: String,
+ required: true,
+ },
+ email: {
+ type: String,
+ required: true,
+ unique: true,
+ },
+ password: {
+ type: String,
+ required: true,
+ },
+ isAdmin: {
+ type: Boolean,
+ required: true,
+ default: false,
+ },
+ pic: {
+ type: String,
+ required: true,
+ default:
+ "https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg",
+ },
+ },
+ {
+ timestamps: true,
+ }
+);
-userSchema.pre('save', async function(next){
- if(!this.isModified('password')){
- next();
- }
+const User = mongoose.model("User", userSchema);
- const salt = await bcrypt.genSalt(10)
- this.password= await bcrypt.hash(this.password,salt);
-})
-userSchema.methods.matchPassword = async function (enteredPassword) {
- return await bcrypt.compare(enteredPassword, this.password);
- };
-
-const User = mongoose.model("User", userSchema)
-
-module.exports = User
\ No newline at end of file
+module.exports = User;
diff --git a/server/routes/userRoutes.js b/server/routes/userRoutes.js
index ac59ad9..8a09e34 100644
--- a/server/routes/userRoutes.js
+++ b/server/routes/userRoutes.js
@@ -2,7 +2,7 @@ const express = require("express")
const {registerUser,authUser} = require('../controllers/userControllers')
const router = express.Router()
-router.route('/').post(registerUser)
+router.route('/register').post(registerUser)
router.route('/login').post(authUser)
diff --git a/server/utill/encryptionUtil.js b/server/utill/encryptionUtil.js
new file mode 100644
index 0000000..2de3de0
--- /dev/null
+++ b/server/utill/encryptionUtil.js
@@ -0,0 +1,19 @@
+const bcrypt = require("bcrypt");
+
+const encryptionUtil = {
+ async encryptPassword(password) {
+ const salt = await bcrypt.genSalt();
+ const encryptedPassword = await bcrypt.hash(password, salt);
+ return { salt, encryptedPassword };
+ },
+
+ async comparePassword(password, salt, encryptedPasswordToCompareTo) {
+ const { encryptedPassword } = await encryptionUtil.encryptPassword(
+ password,
+ salt
+ );
+ return encryptedPassword === encryptedPasswordToCompareTo;
+ },
+};
+
+module.exports = encryptionUtil;