#42 Creating Cart State for Codeswear.com | NextJs Tutorial for Beginners #HarryBhai #codewithharry
_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")))
}
} 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">
<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-full sideCart absolute top-0 right-0 bg-pink-100 px-8 py-10 transform transition-transform 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="flex">
<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>
<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
[slug].js
import { useRouter } from 'next/router'
import { useState } from 'react'
const Post = ({ addToCart }) => {
const router = useRouter()
const { slug } = router.query
const [pin, setPin] = useState()
const [service, setservice] = useState()
const checkServiceability = async () => {
let pins = await fetch('http://localhost:3000/api/pincode')
let pinJson = await pins.json()
if (pinJson.includes(parseInt(pin))) {
setservice(true)
}
else {
setservice(false)
}
}
const onChangePin = (e) => {
setPin(e.target.value)
}
return <>
<section className="text-gray-600 body-font overflow-hidden">
<div className="container px-5 py-16 mx-auto"> <div className="lg:w-4/5 mx-auto flex flex-wrap">
<img alt="ecommerce" className="lg:w-1/2 w-full lg:h-auto px-24 object-cover object-top rounded" src="https://m.media-amazon.com/images/I/616C7eUWKAL._AC_UL480_FMwebp_QL65_.jpg" />
<div className="lg:w-1/2 w-full lg:pl-10 lg:py-6 mt-6 lg:mt-0">
<h2 className="text-sm title-font text-gray-500 tracking-widest">BRAND NAME</h2>
<h1 className="text-gray-900 text-3xl title-font font-medium mb-1">The Catcher in the Rye</h1>
<div className="flex mb-4">
<span className="flex items-center">
<svg fill="currentColor" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" className="w-4 h-4 text-pink-500" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
</svg>
<svg fill="currentColor" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" className="w-4 h-4 text-pink-500" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
</svg>
<svg fill="currentColor" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" className="w-4 h-4 text-pink-500" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
</svg>
<svg fill="currentColor" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" className="w-4 h-4 text-pink-500" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
</svg>
<svg fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" className="w-4 h-4 text-pink-500" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
</svg>
<span className="text-gray-600 ml-3">4 Reviews</span>
</span>
<span className="flex ml-3 pl-3 py-2 border-l-2 border-gray-200 space-x-2s">
<a className="text-gray-500">
<svg fill="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" className="w-5 h-5" viewBox="0 0 24 24">
<path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z"></path>
</svg>
</a>
<a className="text-gray-500">
<svg fill="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" className="w-5 h-5" viewBox="0 0 24 24">
<path d="M23 3a10.9 10.9 0 01-3.14 1.53 4.48 4.48 0 00-7.86 3v1A10.66 10.66 0 013 4s-4 9 5 13a11.64 11.64 0 01-7 2c9 5 20 0 20-11.5a4.5 4.5 0 00-.08-.83A7.72 7.72 0 0023 3z"></path>
</svg>
</a>
<a className="text-gray-500">
<svg fill="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" className="w-5 h-5" viewBox="0 0 24 24">
<path d="M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z"></path>
</svg>
</a>
</span>
</div>
<p className="leading-relaxed">Fam locavore kickstarter distillery. Mixtape chillwave tumeric sriracha taximy chia microdosing tilde DIY. XOXO fam indxgo juiceramps cornhole raw denim forage brooklyn. Everyday carry +1 seitan poutine tumeric. Gastropub blue bottle austin listicle pour-over, neutra jean shorts keytar banjo tattooed umami cardigan.</p>
<div className="flex mt-6 items-center pb-5 border-b-2 border-gray-100 mb-5">
<div className="flex">
<span className="mr-3">Color</span>
<button className="border-2 border-gray-300 rounded-full w-6 h-6 focus:outline-none"></button>
<button className="border-2 border-gray-300 ml-1 bg-gray-700 rounded-full w-6 h-6 focus:outline-none"></button>
<button className="border-2 border-gray-300 ml-1 bg-pink-500 rounded-full w-6 h-6 focus:outline-none"></button>
</div>
<div className="flex ml-6 items-center">
<span className="mr-3">Size</span>
<div className="relative">
<select className="rounded border appearance-none border-gray-300 py-2 focus:outline-none focus:ring-2 focus:ring-pink-200 focus:border-pink-500 text-base pl-3 pr-10">
<option>SM</option>
<option>M</option>
<option>L</option>
<option>XL</option>
</select>
<span className="absolute right-0 top-0 h-full w-10 text-center text-gray-600 pointer-events-none flex items-center justify-center">
<svg fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" className="w-4 h-4" viewBox="0 0 24 24">
<path d="M6 9l6 6 6-6"></path>
</svg>
</span>
</div>
</div>
</div>
<div className="flex">
<span className="title-font font-medium text-2xl text-gray-900">₹499</span>
<button className="flex ml-4 text-white bg-pink-500 border-0 py-2 px-2 md:px-6 focus:outline-none hover:bg-pink-600 rounded">Buy Now</button>
<button onClick={() => { addToCart(slug, 1, 499, 'Wear the Code(XL, Red)', 'XL', "Red") }} className="flex ml-8 text-white bg-pink-500 border-0 py-2 px-2 md:px-6 focus:outline-none hover:bg-pink-600 rounded">Add to Cart</button>
<button className="rounded-full w-10 h-10 bg-gray-200 p-0 border-0 inline-flex items-center justify-center text-gray-500 ml-4">
<svg fill="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" className="w-5 h-5" viewBox="0 0 24 24">
<path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"></path>
</svg>
</button>
</div>
<div className="pin mt-6 flex space-x-2 text-sm">
<input onChange={onChangePin} className='px-2 border-2 border-gray-400 rounded-md ' type="text" placeholder='Enter your pincode' />
<button onClick={checkServiceability} className=' text-white bg-pink-500 border-0 py-2 px-6 focus:outline-none hover:bg-pink-600 rounded'>Check</button>
</div>
{(!service && service != null) && <div className="text-red-700 text-sm mt-3">
Sorry! we do not deliver to this pincode yet
</div>}
{(service && service != null) && < div className="text-green-700 text-sm mt-3">
Yay! This pincode is serviceable
</div>}
</div>
</div>
</div>
</section></>
}
export default Post
Comments
Post a Comment