Skip to content

Commit

Permalink
Merge pull request #14 from ShahandFahad/usermgmt
Browse files Browse the repository at this point in the history
Usermgmt
  • Loading branch information
ShahandFahad authored Feb 11, 2024
2 parents 5f804b4 + fe5b57a commit adb870c
Show file tree
Hide file tree
Showing 24 changed files with 3,084 additions and 78 deletions.
35 changes: 32 additions & 3 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.6.7",
"leaflet": "^1.9.4",
"leaflet-geosearch": "^3.11.0",
"react": "^18.2.0",
Expand Down
40 changes: 21 additions & 19 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import Admin from "./admin/Admin";
import Login from "./components/Auth/Login";
import Signup from "./components/Auth/Signup";
import MainLayout from "./layouts/MainLayout";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import AuthProvider from "./provider/authProvider";
import Routes from "./routes";

function App() {
return (
<>
<Router>
<Routes>
{/* Login Page */}
<Route path="/login" element={<Login />} />
{/* Registeration Page */}
<Route path="/signup" element={<Signup />} />
{/* Client Side */}
<Route path="/*" element={<MainLayout />} />
{/* Admin Panel */}
<Route path="/admin/*" element={<Admin />} />
</Routes>
</Router>
</>
<AuthProvider>
<Routes />
</AuthProvider>
);
}

export default App;

// The Routing Strategy Without Authentication
// <>
// <Router>
// <Routes>
// {/* Login Page */}
// <Route path="/login" element={<Login />} />
// {/* Registeration Page */}
// <Route path="/signup" element={<Signup />} />
// {/* Client Side */}
// <Route path="/*" element={<MainLayout />} />
// {/* Admin Panel */}
// <Route path="/admin/*" element={<Admin />} />
// </Routes>
// </Router>
// </>
171 changes: 168 additions & 3 deletions frontend/src/components/Auth/Login.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,164 @@
import React from "react";
import { Link } from "react-router-dom";
import React, { useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import sun from "../../assets/images/sun.png";

// Import validators
import {
validateEmail,
validateName,
validatePassword,
validateConfirmPassword,
} from "./validate";

import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

import styled from "styled-components";
import axios from "axios";
import { useAuth } from "../../provider/authProvider";
// Custom loader
const Spinner = styled.div`
width: 24px;
height: 24px;
border: 5px solid #fff;
border-bottom-color: transparent;
border-radius: 50%;
display: inline-block;
box-sizing: border-box;
animation: rotation 1s linear infinite;
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
`;

export default function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");

const [emailBorderColor, setEmailBorderColor] = useState({});
const [passwordBorderColor, setPasswordBorderColor] = useState({});

// Auth
const { setToken } = useAuth();
const navigate = useNavigate();

const [isLoading, setIsLoading] = useState(false);

// Toast for unsuccessful user registeration
const notify = (errName) =>
toast.error(`User is not logged in! ${errName}`, {
position: "top-right",
autoClose: 2500,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "colored",
});

// Styles:
// 1) Error Style
const errorStyle = "2px solid red";
// 2) Valid Style
const validStyle = "2px solid green";

// Get user email from input
const handleOnEmailChange = (e) => {
setEmail(e.target.value);

// setEmailBorderColor(!validateEmail(e.target.value) ? "red" : "green");
setEmailBorderColor({
border: `${!validateEmail(e.target.value) ? errorStyle : validStyle}`,
});
};

// Get user password
const handleOnPasswordChange = (e) => {
setPassword(e.target.value);
setPasswordBorderColor({
border: `${validatePassword(e.target.value) ? errorStyle : validStyle}`,
});
};

/**
*
* USER LOGGIN IN
*
*/

const handleLogin = async (e) => {
// Prevent the browser from reloading the page
e.preventDefault();
// User signup data
const loginData = {
email,
password,
};

// Flag for validation: Validate input fileds. If every thing is ok then make request to server
let EVERYTHING_OK = true;

// If email is empty the display red border and toast
if (!loginData.email || !validateEmail(loginData.email)) {
setEmailBorderColor({
border: errorStyle,
});

setEmail("");
EVERYTHING_OK = false;
}

if (password.length < 8) {
setPasswordBorderColor({
border: errorStyle,
});
setPassword("");
EVERYTHING_OK = false;
}
// If Everything is ok then make request to server
if (EVERYTHING_OK) {
setIsLoading(true);
try {
const response = await axios.post(
"http://localhost:8001/api/v1/user/login",
loginData
);

// TODO: Handle Errors properly.

// When login successfull
if (response.status === 200 && response.data.status === "Success") {
console.log("User is logged In!: ", response.status);
console.log(response.data);

// Store user login token
setToken(response.data.token);
// Navigate user to home page
navigate("/", { replace: true });
} else {
console.log("Error logging in!: ", response.data);

// notify user
notify(response.data.name);
}
} catch (error) {
notify(error.name);
} finally {
setIsLoading(false);
}
}
};
return (
<div className="min-h-screen bg-gray-100 py-6 flex flex-col justify-center sm:py-12">
{/* Error Toast Container: When login Fails, It will notify user */}
<ToastContainer />
<div className="relative py-3 sm:max-w-xl sm:mx-auto">
<div className="relative px-4 py-10 bg-white mx-8 md:mx-0 shadow rounded-3xl sm:p-10">
<div className="max-w-md mx-auto">
Expand All @@ -21,21 +175,30 @@ export default function Login() {
</div>
<div className="divide-y divide-gray-200">
<div className="py-8 text-base leading-6 space-y-4 text-gray-700 sm:text-lg sm:leading-7">
{/* EMAIL INPUT */}
<div className="flex flex-col">
<label className="leading-loose">Email Address</label>
<input
type="email"
className="px-4 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600"
placeholder="Email address"
value={email}
onChange={handleOnEmailChange}
// style={{ border: `1.5px solid ${emailBorderColor}` }}
style={emailBorderColor}
/>
</div>
{/* PASSWORD INPUT */}
<div className="flex flex-col">
<label className="leading-loose">Password</label>
<div className="relative focus-within:text-gray-600 text-gray-400">
<input
type="password"
className="pr-4 pl-10 py-2 border focus:ring-gray-500 focus:border-gray-900 w-full sm:text-sm border-gray-300 rounded-md focus:outline-none text-gray-600"
placeholder="Password"
value={password}
onChange={handleOnPasswordChange}
style={passwordBorderColor}
/>
<div className="absolute left-3 top-2">
<svg
Expand Down Expand Up @@ -80,8 +243,10 @@ export default function Login() {
<button
style={{ background: "#f76b1c" }}
className="flex justify-center items-center w-full text-white px-4 py-3 rounded-md focus:outline-none"
onClick={handleLogin}
>
Login
{/* If no laading display "Register". If loading Display spinner */}
{!isLoading ? "Login" : <Spinner />}
</button>
</div>

Expand Down
61 changes: 61 additions & 0 deletions frontend/src/components/Auth/Logout.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from "react";
import axios from "axios";
import { useAuth } from "../../provider/authProvider";
import { useNavigate } from "react-router-dom";
import styled from "styled-components";
// Custom loader
const Spinner = styled.div`
width: 80px;
height: 80px;
border: 10px solid #f76b1c;
border-bottom-color: transparent;
border-radius: 50%;
display: inline-block;
box-sizing: border-box;
animation: rotation 1s linear infinite;
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
`;

const LogOut = styled.div`
display: flex;
flex-direction: column;
gap: 5px;
width: 100%;
height: 100vh;
justify-content: center;
align-items: center;
`;

const Logout = () => {
const { setToken } = useAuth();
const navigate = useNavigate();

// Just remove the token from local storage and navigate back to login page
const handleLogout = () => {
setToken();
navigate("/login", { replace: true });
};

// Wait for 5 sec
setTimeout(() => {
handleLogout();
console.log("User Logged Out.");
}, 1500);

return (
<LogOut>
<Spinner />
<h1>LOGGING OUT...</h1>
</LogOut>
);
};

export default Logout;
Loading

0 comments on commit adb870c

Please sign in to comment.