Business Scenario
Hello talented developers!
ShopKart has successfully implemented its Products Page, where customers can discover products through, apply filters ,etc
However, the current Navbar does not provide a proper way for a customer to access their account.
An e-commerce application should provide customers with options such as:
Therefore, in this lab we will introduce an Account/Profile section in the ShopKart Navbar.
Pre-Lab Preparation
Module:
1) Handling Side-Effects
2) Handling Forms in React
git pull origin branchNameGit Pull
Task 1 : Simplify the ShopKart Navbar
Currently, the Navbar contains:
Remove All Categories
1
We don't need the category dropdown in the Navbar because product categories are already handled on the Products page.
Remove the wishlist icon from navbar
2
Add Profile Icon
3
Place the profile section after Cart.
<div className="dropdown account-dropdown">
<button className="account-btn" type="button" data-bs-toggle="dropdown"
aria-expanded="false" aria-label="My Account">
<img src="/icons/profile-icon.png" alt="My Account" className="profile-icon" />
</button>
<ul className="dropdown-menu account-menu">
<li> <a className="dropdown-item" href="/login">Login</a> </li> <li>
<a className="dropdown-item" href="/register">Register</a>
</li>
</ul>
</div>Style the Account Section
4
Task 2 : Connect Login and Register Pages
/login
/register
In App.jsx, add:
1
import Login from "./pages/Login";
import Register from "./pages/Register";Then :
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />Plan the Login Form Workflow
2
User opens Login page
Enters username and passwords
Submits form
Form validation runs
Username is passed using setUserName()
User is redirected to Home
Navbar displays "Hello, Username"
Task 3 : Create the Login Form
Open Login.jsx and add imports:
1
import React from "react";
import { useForm } from "react-hook-form";And inside the component add :
const { register, handleSubmit, formState: { errors }} = useForm();useForm() provides the functionality required to:
Create the Login Form with Validation
2
import React from "react";
import { useForm } from "react-hook-form";
import "./Login.css";
function Login({ setUserName }) {
const { register, handleSubmit, formState: { errors }} = useForm();
return (
<div className="login-page">
<div className="login-container">
<div className="login-logo">
<img src="/images/logo.png" alt="ShopKart" />
</div>
<h2>Welcome Back!</h2>
<p className="login-subtitle"> Login to continue shopping with ShopKart </p>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="form-group">
<label>Username</label> <input type="text" placeholder="Enter your username"
{...register("username", {
required: "Username is required" })} />
{errors.username && (
<p className="form-error">
{errors.username.message}
</p>
)}
</div>
<div className="form-group">
<label>Password</label>
<input type="password" placeholder="Enter your password"
{...register("password", {
required: "Password is required",
minLength: {
value: 6,
message: "Password must be at least 6 characters"
}
})}
/>
{errors.password && (
<p className="form-error">
{errors.password.message}
</p>
)}
</div> <button type="submit"> Login </button>
</form>
<p className="register-text"> Don't have an account? <a href="/register">
Register</a> </p>
</div>
</div>
);
}
export default Login;Why are we using setUsername ?
setUserName as a prop.setUserName(data.username);Handle successful form submission
2
const onSubmit = (data) => {
setUserName(data.username);
};
Style the login form
3
Task 4 : Create the Registeration Form
Open Register.jsx and add :
1
import React from "react";
import { useForm } from "react-hook-form";
import "./Register.css";
function Register({ setUserName }) {
const { register,handleSubmit,formState: { errors }} = useForm();
};
return (
<div className="register-page">
<div className="register-container">
<div className="register-logo">
<img src="/images/logo.png" alt="ShopKart"/>
</div>
<h2>Create Your Account</h2>
<p className="register-subtitle"> Register to start shopping with ShopKart </p> <form onSubmit={handleSubmit(onSubmit)}>
<div className="form-group">
<label>Full Name</label>
<input type="text" placeholder="Enter your full name"
{...register("fullName", {
required: "Full name is required"
})}
/>
{errors.fullName && (
<p className="form-error"> {errors.fullName.message}</p>
)}
</div>
<div className="form-group">
<label>Username</label>
<input type="text" placeholder="Enter your username"
{...register("username", {
required: "Username is required"
})}
/>
{errors.username && (
<p className="form-error"> {errors.username.message}</p>
)}
</div>
<div className="form-group">
<label>Email</label> <input type="email" placeholder="Enter your email"
{...register("email", {
required: "Email is required"
})}
/>
{errors.email && (
<p className="form-error">
{errors.email.message}
</p>
)}
</div>
<div className="form-group">
<label>Password</label>
<input type="password" placeholder="Create a password"
{...register("password", {
required: "Password is required",
minLength: {
value: 6,
message: "Password must be at least 6 characters"
}
})}/>
{errors.password && (
<p className="form-error">{errors.password.message} </p>
)}
</div> <div className="form-group">
<label>Confirm Password</label>
<input type="password" placeholder="Confirm your password"
{...register("confirmPassword", {
required: "Please confirm your password"
})}
/>
{errors.confirmPassword && (
<p className="form-error"> {errors.confirmPassword.message} </p>
)}
</div>
<button type="submit"> Register </button>
</form>
<p className="login-text"> Already have an account? <a href="/login"> Login</a>
</p>
</div>
</div>
);
}
export default Register;Handle successful form submission
2
const onSubmit = (data) => {
if (data.password === data.confirmPassword) {
setUserName(data.username);
} else {
alert("Passwords do not match");
}
};
Why are we using if...else here ?
We use if...else to compare the Password and Confirm Password values after the
other form validations have passed.
Style the Register form
3
Task 5 : Introduce useState
1
import React, { useState } from "react";useState in App.jsx because the username needs to be available to both the Login/Register pages and the Navbar.Add this import at the top
2
Inside App() add:
const [userName, setUserName] = useState("");3
Connect Login & Register Using setUserName
Now we pass setUserName from App.jsx to Login and Register.
Change:
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />To :
<Route path="/login" element={<Login setUserName={setUserName} />}/>
<Route path="/register" element={<Register setUserName={setUserName} />} />Task 6 : Use useNavigate for Redirect
1
Open Login.jsx and import useNavigate
import { useNavigate } from "react-router-dom";2
Initialize the useNavigate hook inside your component.
const navigate = useNavigate();const onSubmit = (data) => {
setUserName(data.username);
navigate("/");
};3
Update form submission
1
Open Register.jsx and import useNavigate
const navigate = useNavigate();2
Initialize the useNavigate hook inside your component.
import { useNavigate } from "react-router-dom";3
Update form submission
const onSubmit = (data) => {
if (data.password === data.confirmPassword) {
setUserName(data.username);
navigate("/");
} else {
alert("Passwords do not match");
}
};Task 7 : Render Navbar from App.jsx
Navbar was rendered inside Home.jsx and Products.jsx.App.jsx.Why are we doing this?
App.jsx contains : const [userName, setUserName] = useState("");
userName to display:Hello, Username
Home.jsx, we would have to pass userName:App.jsx(userName) --> Home.jsx(userName) --> Navbar.jsx
App.jsx
userName state
Navbar --> Hello, Username
1
Update App.jsx
import Navbar from "./components/Navbar";<Routes> <Navbar userName={userName} />
<Routes>
---
</Routes>2
Remove Navbar from Home and Products
3
Receive userName in Navbar
function Navbar() {
function Navbar({userName}) {
Task 8 : Display Greeting
1
Open Navbar.jsx - In your account/profile section, use:
{/* Account / Greeting */}
{userName ? (
<span className="user-greeting">
<img src="/icons/profile-icon.png" alt="Profile" className="greeting-profile-icon" />
Hello, {userName}
</span>
) : (
<div className="dropdown account-dropdown">
<button className="account-btn" type="button" data-bs-toggle="dropdown"
aria-expanded="false" aria-label="My Account">
<img src="/icons/profile-icon-2.png" alt="My Account" className="profile-icon" />
</button>
<ul className="dropdown-menu account-menu">
<li><a className="dropdown-item" href="/login">Login</a></li>
<li><a className="dropdown-item" href="/register">Register</a></li>
</ul>
</div>
)}2
Style the Greetings section
Task 9 : Use React Router Links for Navbar Navigation
<a href=""> links with React Router's Link and NavLink.Why are we doing this?
userName stored in useState is reset.1
In Navbar.jsx import :
import { Link, NavLink } from "react-router-dom";2
Use NavLink for the main page navigation:
<NavLink className="nav-link" to="/"> Home </NavLink>
<NavLink className="nav-link" to="/products"> Products </NavLink>
<NavLink className="nav-link" to="/about"> About </NavLink>
<NavLink className="nav-link" to="/contact"> Contact </NavLink>
<NavLink className="nav-link" to="/cart"> Cart </NavLink>3
Use Link for the logo , login and register
<Link className="navbar-brand" to="/">
<img src="/images/logo.png" alt="ShopKart" className="shopkart-logo"/>
</Link>
<Link className="dropdown-item" to="/login"> Login </Link>
<Link className="dropdown-item" to="/register"> Register </Link>4
Add this at the end of Navbar.css
.navbar .nav-link.active {
color: #0aa89e;
position: relative;
}
.navbar .nav-link.active::after {
content: "";
position: absolute; left: 5px;
right: 5px;
bottom: 2px;
height: 2px;
background-color: #0aa89e;
border-radius: 2px;
}Task 10 : Connect Trending Link to Home Section
The Trending 🔥 Navbar link is not a separate page. It points to the Trending Products section inside the Home page.
But the problem is: If we are on the Products page and click the Trending link, nothing happens.
#trending section does not exist on the Products page.Solution :
We will make the link:
If already on Home → scroll to Trending
If on another page → go to Home → scroll to Trending
1
Update the Navbar.jsx import
import { Link, NavLink, useNavigate } from "react-router-dom";Then inside the Navbar :
function Navbar({ userName }) {
const navigate = useNavigate();
// existing code
}2
Now Replace the Trending link with:
<a
className="nav-link"
href="#trending"
onClick={(e) => {
e.preventDefault();
if (window.location.pathname === "/") {
document.getElementById("trending")?.scrollIntoView({behavior: "smooth"});
} else {
navigate("/");
setTimeout(() => {
document.getElementById("trending")?.scrollIntoView({
behavior: "smooth"
});
}, 100);
}
}}
>
Trending 🔥
</a> the user is already on the Home page.2. document.getElementById("trending")?.scrollIntoView({ behavior: "smooth" });
3. else { navigate("/");
/products" or another page, we first navigate them back to:"/"id="trending" and scrolls to it.behavior: "smooth" which makes the scrolling animated instead of jumping instantly.
4. setTimeout(() => {
#trending.5. document.getElementById("trending")?.scrollIntoView({ behavior: "smooth" });
We are done with this lab. The latest source code has been uploaded to GitHub. You can access the latest commit using the link below:
Great job!
Your ShopKart Login, Registration & Forms are now working smoothly with validation, navigation.
Checkpoint
Git Push
git push origin branchNameNext-Lab Preparation
Module:
1) Handling Side-Effects
2) React Context & Reducers