#43 Improving Sidebar & Checkout Page for Codeswear.com | NextJs Tutorial for Beginners
_app.js
import { useEffect, useState } from 'react'
import Footer from '../components/Footer'
import Navbar from '../components/Navbar'
import '../styles/globals.css'
function MyApp({ Component, pageProps }) {
const [cart, setCart] = useState({})
const [subTotal, setSubTotal] = useState(0)
useEffect(() => {
console.log("Hey I am a useEffect form _app.js")
try {
if (localStorage.getItem("cart")) {
setCart(JSON.parse(localStorage.getItem("cart")))
saveCart(JSON.parse(localStorage.getItem("cart")))
}
} catch (error) {
console.error(error);
localStorage.clear()
}
}, [])
const saveCart = (myCart) => {
localStorage.setItem("cart", JSON.stringify(myCart))
let subt = 0;
let keys = Object.keys(myCart)
for (let i = 0; i < keys.length; i++) {
subt += myCart[keys[i]].price * myCart[keys[i]].qty;
}
setSubTotal(subt)
}
const addToCart = (itemCode, qty, price, name, size, variant) => {
let newCart = cart;
if (itemCode in cart) {
newCart[itemCode].qty = cart[itemCode].qty + qty
}
else {
newCart[itemCode] = { qty: 1, price, name, size, variant }
}
setCart(newCart)
saveCart(newCart)
}
const clearCart = () => {
setCart({})
saveCart({})
}
const removeFromCart = (itemCode, qty, price, name, size, variant) => {
let newCart = JSON.parse(JSON.stringify(cart));
if (itemCode in cart) {
newCart[itemCode].qty = cart[itemCode].qty - qty
}
if (newCart[itemCode]["qty"] <= 0) {
delete newCart[itemCode]
}
setCart(newCart)
saveCart(newCart)
}
return <>
<Navbar cart={cart} addToCart={addToCart} removeFromCart={removeFromCart} clearCart={clearCart} subTotal={subTotal} />
<Component cart={cart} addToCart={addToCart} removeFromCart={removeFromCart} clearCart={clearCart} subTotal={subTotal} {...pageProps} />
<Footer />
</>
}
export default MyApp
Navbar.js
import React from 'react'
import Image from 'next/image'
import Link from 'next/link'
import { useRef } from 'react';
import { AiOutlineShoppingCart, AiFillCloseCircle, AiFillPlusCircle, AiFillMinusCircle } from 'react-icons/ai';
import { BsFillBagCheckFill } from 'react-icons/bs';
const Navbar = ({ cart, addToCart, removeFromCart, clearCart, subTotal }) => {
console.log(cart, addToCart, removeFromCart, clearCart, subTotal)
const toggleCart = () => {
if (ref.current.classList.contains('translate-x-full')) {
ref.current.classList.remove('translate-x-full')
ref.current.classList.add('translate-x-0')
}
else if (!ref.current.classList.contains('translate-x-full')) {
ref.current.classList.remove('translate-x-0')
ref.current.classList.add('translate-x-full')
}
}
const ref = useRef()
return (
<div className="flex flex-col md:flex-row md:justify-start justify-center items-center py-2 shadow-md sticky top-0 bg-white z-10">
<div className="logo mx-5">
<Link href={'/'}><a><Image width={200} height={40} src="/logo.webp" alt="" /></a></Link>
</div>
<div className="nav ">
<ul className='flex items-center space-x-6 font-bold md:text-sm'>
<Link href={'/tshirts'}><a><li>Tshirts</li></a></Link>
<Link href={'/hoodies'}><a><li>Hoodies</li></a></Link>
<Link href={'/stickers'}><a><li>Stickers</li></a></Link>
<Link href={'/mugs'}><a><li>Mugs</li></a></Link>
</ul>
</div>
<div onClick={toggleCart} className=" cursor-pointer cart absolute right-0 top-4 mx-5">
<AiOutlineShoppingCart className='text-xl md:text-2xl' />
</div>
<div ref={ref} className={`w-72 h-[100vh] sideCart absolute top-0 right-0 bg-pink-100 px-8 py-10 transform transition-transform ${Object.keys(cart).length !==0 ? `translate-x-0`: `translate-x-full`}`}>
<h2 className="font-bold text-xl text-center">Shoping Cart</h2>
<span onClick={toggleCart} className='absolute top-5 right-2 cursor-pointer text-2xl text-pink-500'><AiFillCloseCircle /></span>
<ol className='list-decimal font-semibold'>
{Object.keys(cart).length == 0 && <div className='my-4 font-semibold'>Your cart is Empty!</div>}
{Object.keys(cart).map((k) => {
return <li keys={k}>
<div className='item flex my-5'>
<div className="w-2/3 font-semibold">{cart[k].name} </div>
<div className="flex font-semibold item-center justify-center w-1/3 text-lg"><AiFillMinusCircle onClick={() => { removeFromCart(k, 1, cart[k].price, cart[k].name, cart[k].size, cart[k].variant) }} className='cursor-pointer text-pink-500' /><span className='mx-2 text-sm'>{cart[k].qty}</span><AiFillPlusCircle onClick={() => { addToCart(k, 1, cart[k].price, cart[k].name, cart[k].size, cart[k].variant) }} className='cursor-pointer text-pink-500' /></div>
</div>
</li>
})}
</ol>
<div className="font-bold py-2 ">Subtotal:{subTotal}</div>
<div className="flex">
<Link href={'/checkout'}><button className='flex mr-2 text-white bg-pink-500 border-0 py-4 px-2 focus:outline-none hover:bg-pink-600 rounded text-sm '><BsFillBagCheckFill className='m-1' />Checkout</button></Link>
<button onClick={clearCart} className='flex mr-2 text-white bg-pink-500 border-0 py-2 px-8 focus:outline-none hover:bg-pink-600 rounded text-sm'>Clear Cart</button>
</div>
</div>
</div>
)
}
export default Navbar
Checkout.js
import React from 'react'
import { AiFillPlusCircle, AiFillMinusCircle } from 'react-icons/ai';
import { BsFillBagCheckFill } from 'react-icons/bs';
import Link from 'next/link';
const Checkout = ({ cart, subTotal, addToCart, removeFromCart }) => {
return (
<div className='container px-2 sm:m-auto'>
<h1 className='font-bold text-xl my-8 text-center'>Checkout</h1>
<h2 className='font-semibold text-xl '>1. Delivery Details</h2>
<div className="mx-auto flex my-2">
<div className="px-2 w-1/2">
<div className=" mb-4">
<label htmlFor="name" className="leading-7 text-sm text-gray-600">Name</label>
<input type="text" id="name" name="name" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
<div className="px-2 w-1/2">
<div className=" mb-4">
<label htmlFor="email" className="leading-7 text-sm text-gray-600">Email</label>
<input type="email" id="email" name="email" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
</div>
<div className="px-2 w-full">
<div className=" mb-4">
<label htmlFor="address" className="leading-7 text-sm text-gray-600">Address</label>
<textarea name="" id="" cols="30" rows="2" id="email" name="email" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"></textarea>
</div>
</div>
<div className="mx-auto flex my-2">
<div className="px-2 w-1/2">
<div className=" mb-4">
<label htmlFor="phone" className="leading-7 text-sm text-gray-600">Phone</label>
<input type="text" id="phone" name="phone" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
<div className="px-2 w-1/2">
<div className=" mb-4">
<label htmlFor="city" className="leading-7 text-sm text-gray-600">City</label>
<input type="text" id="city" name="city" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
</div>
<div className="mx-auto flex my-2">
<div className="px-2 w-1/2">
<div className=" mb-4">
<label htmlFor="state" className="leading-7 text-sm text-gray-600">State</label>
<input type="text" id="state" name="state" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
<div className="px-2 w-1/2">
<div className=" mb-4">
<label htmlFor="pincode" className="leading-7 text-sm text-gray-600">Pincode</label>
<input type="text" id="pincode" name="pincode" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
</div>
<h2 className='font-semibold text-xl '>2. Review Cart Items & Pay</h2>
<div className="sideCart bg-pink-100 py-6 my-4 ">
<ol className='list-decimal font-semibold mx-12'>
{Object.keys(cart).length == 0 && <div className='my-4 font-semibold'>Your cart is Empty!</div>}
{Object.keys(cart).map((k) => {
return <li keys={k}>
<div className='item flex my-5'>
<div className="font-semibold">{cart[k].name} </div>
<div className="flex font-semibold item-center justify-center w-1/3 text-lg"><AiFillMinusCircle onClick={() => { removeFromCart(k, 1, cart[k].price, cart[k].name, cart[k].size, cart[k].variant) }} className='cursor-pointer text-pink-500' /><span className='mx-2 text-sm'>{cart[k].qty}</span><AiFillPlusCircle onClick={() => { addToCart(k, 1, cart[k].price, cart[k].name, cart[k].size, cart[k].variant) }} className='cursor-pointer text-pink-500' /></div>
</div>
</li>
})}
</ol>
<div className="font-bold mx-10">Subtotal:{subTotal}</div>
</div>
<div className="mx-4">
<Link href={'/checkout'}><button className='flex mr-2 text-white bg-pink-500 border-0 py-4 px-2 focus:outline-none hover:bg-pink-600 rounded text-sm '><BsFillBagCheckFill className='m-1' />Pay ₹ {subTotal}</button></Link>
</div>
</div>
)
}
export default Checkout
Comments
Post a Comment