Skip to content

Instantly share code, notes, and snippets.

@adrianhajdin
Last active July 11, 2024 14:11
Show Gist options
  • Save adrianhajdin/55e019f0ec6a48c0ca6d933d3cf0181c to your computer and use it in GitHub Desktop.
Save adrianhajdin/55e019f0ec6a48c0ca6d933d3cf0181c to your computer and use it in GitHub Desktop.
Build and Deploy a Modern Full Stack ECommerce Application with Stripe
export default {
name: 'banner',
title: 'Banner',
type: 'document',
fields: [
{
name: 'image',
title: 'Image',
type: 'image',
options: {
hotspot: true,
},
},
{
name: 'buttonText',
title: 'ButtonText',
type: 'string',
},
{
name: 'product',
title: 'Product',
type: 'string',
},
{
name: 'desc',
title: 'Desc',
type: 'string',
},
{
name: 'smallText',
title: 'SmallText',
type: 'string',
},
{
name: 'midText',
title: 'MidText',
type: 'string',
},
{
name: 'largeText1',
title: 'LargeText1',
type: 'string',
},
{
name: 'largeText2',
title: 'LargeText2',
type: 'string',
},
{
name: 'discount',
title: 'Discount',
type: 'string',
},
{
name: 'saleTime',
title: 'SaleTime',
type: 'string',
},
],
};
html,
body, * {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
box-sizing: border-box;
}
::-webkit-scrollbar {
width: 0px;
}
a {
color: inherit;
text-decoration: none;
}
.main-container{
max-width: 1400px;
margin: auto;
width: 100%;
}
.layout{
padding: 10px;
}
.navbar-container{
display: flex;
justify-content: space-between;
margin: 6px 18px;
position: relative;
}
.marquee-text{
font-size: 29px;
font-weight: 600;
margin: 60px 0px;
color: #f02d34;
}
.marquee {
position: relative;
height: 400px;
width: 100%;
overflow-x: hidden;
}
.track {
position: absolute;
white-space: nowrap;
will-change: transform;
animation: marquee 15s linear infinite;
width: 180%;
}
.track:hover {
animation-play-state: paused;
}
@keyframes marquee {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
span.text-red {
-webkit-text-stroke: 1px #f02d34;
margin-left: 6px;
}
.logo{
color: gray;
font-size: 18px;
}
.cart-icon{
font-size: 25px;
color: gray;
cursor: pointer;
position: relative;
transition: transform .4s ease;
border: none;
background-color: transparent;
}
.cart-icon:hover{
transform: scale(1.1,1.1);
}
.cart-item-qty{
position: absolute;
right: -8px;
font-size: 12px;
color: #eee;
background-color: #f02d34;
width: 18px;
height: 18px;
border-radius: 50%;
text-align: center;
font-weight: 600;
}
.products-container{
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 15px;
margin-top: 20px;
width: 100%;
}
.product-card{
cursor: pointer;
transform: scale(1, 1);
transition: transform 0.5s ease;
color: #324d67;
}
.product-card:hover{
transform: scale(1.1,1.1)
}
.product-image{
border-radius: 15px;
background-color: #ebebeb;
transform: scale(1, 1);
transition: transform 0.5s ease;
}
.product-name{
font-weight: 500;
}
.product-price{
font-weight: 800;
margin-top: 6px;
color: black;
}
.hero-banner-container{
padding: 100px 40px;
background-color: #dcdcdc;
border-radius: 15px;
position: relative;
height: 500px;
line-height: 0.9;
width: 100%;
}
.hero-banner-container .beats-solo{
font-size: 20px;
}
.hero-banner-container button{
border-radius: 15px;
padding: 10px 16px;
background-color: #f02d34;
color: white;
border: none;
margin-top: 40px;
font-size: 18px;
font-weight: 500;
cursor: pointer;
z-index:10000 !important;
}
.hero-banner-container h3{
font-size: 4rem;
margin-top: 4px;
}
.hero-banner-container h1{
color: white;
font-size: 10em;
margin-left: -20px;
text-transform: uppercase;
}
.hero-banner-image{
position: absolute;
top: 0%;
right:20%;
width: 450px;
height: 450px;
}
.desc{
position: absolute;
right: 10%;
bottom: 5%;
width: 300px;
line-height: 1.3;
display: flex;
flex-direction: column;
color: #324d67;
}
.desc p{
color: #5f5f5f;
font-weight: 100;
text-align: end;
}
.desc h5{
margin-bottom: 12px;
font-weight: 700;
font-size: 16px;
/* color: black; */
align-self: flex-end;
}
.products-heading{
text-align: center;
margin: 40px 0px;
color: #324d67;
}
.products-heading h2{
font-size: 40px;
font-weight: 800;
}
.products-heading p{
font-size: 16px;
font-weight: 200;
}
.footer-banner-container{
padding: 100px 40px;
background-color: #f02d34;
border-radius: 15px;
position: relative;
height: 400px;
line-height: 1;
color: white;
width: 100%;
margin-top: 120px;
}
.banner-desc{
display: flex ;
justify-content: space-between;
}
.banner-desc button{
border-radius: 15px;
padding: 10px 16px;
background-color: white;
color: red;
border: none;
margin-top: 40px;
font-size: 18px;
font-weight: 500;
cursor: pointer;
}
.banner-desc .left h3{
font-weight: 900;
font-size: 80px;
margin-left: 25px;
}
.banner-desc .left p{
margin:18px;
}
.footer-banner-image{
position: absolute;
/* top: -35%;
left: 8%; */
top: -25%;
left: 25%;
}
.banner-desc .right{
line-height: 1.4;
}
.banner-desc .right h3{
font-weight: 800;
font-size: 60px;
}
.banner-desc .right p{
font-size: 18px;
}
.banner-desc .right .company-desc{
font-size: 14px;
font-weight: 300;
}
.cart-wrapper{
width: 100vw;
background: rgba(0, 0, 0, 0.5);
position: fixed;
right: 0;
top: 0;
z-index: 100;
/* will-change: transform; */
transition: all 1s ease-in-out;
}
.cart-container{
height: 100vh;
width: 600px;
background-color: white;
float: right;
padding: 40px 10px;
position: relative;
}
.footer-container{
color: #324d67;
text-align: center;
margin-top: 20px;
padding: 30px 10px;
font-weight: 700;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
justify-content: center;
}
.footer-container .icons{
font-size: 30px;
display: flex;
gap: 10px;
}
.cart-heading{
display: flex;
align-items: center;
font-size: 18px;
font-weight: 500;
cursor: pointer;
gap: 2px;
margin-left: 10px;
border: none;
background-color: transparent;
}
.cart-heading .heading{
margin-left: 10px;
}
.cart-num-items{
margin-left: 10px;
color: #f02d34;
}
.empty-cart{
margin:40px;
text-align:center;
}
.empty-cart h3{
font-weight: 600;
font-size: 20px;
}
.cancel{
cursor: pointer;
}
.product-container{
margin-top: 15px;
overflow: auto;
max-height: 70vh;
padding: 20px 10px;
}
.product{
display: flex;
gap: 30px;
padding: 20px;
}
.product .cart-product-image{
width:180px ;
height: 150px;
border-radius: 15px;
background-color: #ebebeb;
}
.item-desc .flex{
display: flex;
justify-content: space-between;
width: 350px;
color: #324d67;
}
.item-desc .bottom{
margin-top: 60px;
}
.flex h5{
font-size: 24px;
}
.flex h4{
font-size: 20px;
}
.total{
display: flex;
justify-content: space-between;
}
.total h3{
font-size: 22px;
}
.remove-item{
font-size: 24px;
color: #f02d34;
cursor: pointer;
background: transparent;
border: none;
}
.cart-bottom{
position: absolute;
bottom: 12px;
right: 5px;
width: 100%;
padding: 30px 65px;
}
.btn-container{
width: 400px;
margin: auto;
}
.btn{
width: 100%;
max-width: 400px;
padding: 10px 12px;
border-radius: 15px;
border: none;
font-size: 20px;
margin-top: 10px;
margin-top: 40px;
text-transform: uppercase;
background-color: #f02d34;
color: #fff;
cursor: pointer;
transform: scale(1, 1);
transition: transform 0.5s ease;
}
.btn:hover{
transform: scale(1.1,1.1);
}
.product-detail-container{
display: flex;
gap: 40px;
margin: 40px;
margin-top: 60px;
color: #324d67;
}
.product-detail-image{
border-radius: 15px;
background-color: #ebebeb;
width: 400px;
height: 400px;
cursor: pointer;
transition: .3s ease-in-out;
}
.product-detail-image:hover{
background-color: #f02d34;
}
.small-images-container{
display: flex;
gap: 10px;
margin-top: 20px;
}
.small-image{
border-radius: 8px;
background-color: #ebebeb;
width: 70px;
height: 70px;
cursor: pointer;
}
.selected-image{
background-color:#f02d34;
}
.reviews{
color: #f02d34;
margin-top: 10px;
display: flex;
gap: 5px;
align-items: center;
}
.product-detail-desc h4{
margin-top: 10px;
}
.product-detail-desc p{
margin-top: 10px;
}
.reviews p{
color: #324d67;
margin-top: 0px;
}
.product-detail-desc .price{
font-weight: 700 ;
font-size: 26px;
margin-top: 30px;
color:#f02d34;
}
.price .old-price, .product-price .old-price, .price .old-price{
color: gray;
text-decoration: line-through;
}
.product-detail-desc .quantity{
display: flex;
gap: 20px;
margin-top: 10px ;
align-items: center;
}
.product-detail-desc .buttons{
display: flex;
gap: 30px;
}
.buttons .add-to-cart{
padding: 10px 20px;
border: 1px solid #f02d34 ;
margin-top: 40px;
font-size: 18px;
font-weight: 500;
background-color: white;
color: #f02d34;
cursor: pointer;
width: 200px;
transform: scale(1, 1);
transition: transform 0.5s ease;
}
.buttons .add-to-cart:hover{
transform:scale(1.1,1.1)
}
.buttons .buy-now{
width: 200px;
padding: 10px 20px;
background-color: #f02d34;
color: white;
border: none;
margin-top: 40px;
font-size: 18px;
font-weight: 500;
cursor: pointer;
transform: scale(1, 1);
transition: transform 0.5s ease;
}
.buttons .buy-now:hover{
transform:scale(1.1,1.1)
}
.quantity-desc{
border: 1px solid gray;
padding: 6px;
}
.quantity-desc span{
font-size: 16px;
padding: 6px 12px;
cursor: pointer;
}
.quantity-desc .minus{
border-right: 1px solid gray;
color: #f02d34;
}
.quantity-desc .num{
border-right: 1px solid gray;
font-size: 20px;
}
.quantity-desc .plus{
color: rgb(49, 168, 49);
}
.maylike-products-wrapper{
margin-top: 120px;
}
.maylike-products-wrapper h2{
text-align: center;
margin: 50px;
color: #324d67;
font-size: 28px;
}
.maylike-products-container{
display: flex;
justify-content: center;
gap: 15px;
margin-top: 20px;
}
.max-qty{
font-weight: 500;
color: #f02d34;
}
.success-wrapper, .cancel-wrapper{
background-color: white;
min-height: 60vh;
}
.success, .cancel{
width: 1000px;
margin: auto;
margin-top: 160px;
background-color: #dcdcdc;
padding: 50px;
border-radius: 15px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.success .icon {
color: green;
font-size: 40px;
}
.success h2{
text-transform: capitalize;
margin-top: 15px 0px;
font-weight: 900;
font-size: 40px;
color:#324d67;
}
.success .email-msg{
font-size: 16px;
font-weight: 600;
text-align: center;
}
.cancel p{
font-size: 20px;
font-weight: 600;
}
.success .description{
font-size: 16px;
font-weight: 600;
text-align: center;
margin: 10px;
margin-top: 30px;
}
.success .description .email{
margin-left: 5px;
color: #f02d34;
}
.product-max-qty{
margin-top: 10px;
}
@media screen and (max-width:800px) {
.hero-banner-container{
height: 560px;
}
.hero-banner-image{
width: 77%;
height: 62%;
top: -2%;
right: -6%;
}
.footer-banner-container{
height: 560px;
margin-top: 80px;
}
.footer-banner-image{
width: 77%;
left: 30%;
top: 6%;
height: 56%
}
.banner-desc .left h3{
font-weight: 900;
font-size: 50px;
margin-left: 5px;
}
.banner-desc .left p{
margin:18px;
}
.banner-desc .right h3{
font-size: 45px;
}
.banner-desc .right p{
font-size: 18px;
}
.banner-desc .right .company-desc{
font-size: 14px;
}
.banner-desc{
flex-wrap: wrap;
gap: 20px;
}
.hero-banner-container{
line-height: 1.3;
}
.hero-banner-container h1{
font-size: 50px;
}
.hero-banner-container h3{
font-size: 40px;
}
.hero-banner-container button{
margin-top: 90px;
z-index: 10000;
}
.desc{
bottom: 60px;
}
.product-detail-container{
flex-wrap: wrap;
}
.product-detail-container .product-detail-image{
width: 350px;
height: 350px;
}
.cart-container{
width: 415px;
padding: 4px;
}
.cart-heading{
margin-top: 35px;
}
.product-container{
margin-top: 10px;
}
.product{
padding: 20px 5px;
}
.product .cart-product-image{
width: 25%;
height: 25%;
}
.buttons .add-to-cart{
width: 150px;
}
.buttons .buy-now{
width: 150px;
}
.product-detail-container{
margin: 20px;
}
.item-desc .flex{
width: 200px;
}
.top{
flex-wrap: wrap;
gap: 10px;
}
.item-desc .bottom{
margin-top: 30px;
}
.flex h5{
font-size: 16px;
color: #324d67;
}
.flex h4{
font-size: 16px;
color: black;
}
.cart-bottom{
padding: 30px;
}
.total h3{
font-size: 20px;
}
.track {
animation: marquee 10s linear infinite;
width: 550%;
}
.success-wrapper, .cancel-wrapper{
min-height: 69vh;
}
.success, .cancel {
width: 370px;
margin-top: 100px;
padding: 20px;
}
.success{
height: 350px;
}
.success h2{
font-size: 17px;
}
.btn-container{
width: 300px;
margin: auto;
}
}
{
"name": "sanity-ecommerce",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@sanity/client": "^3.2.0",
"@sanity/image-url": "^1.0.1",
"@stripe/stripe-js": "^1.25.0",
"canvas-confetti": "^1.5.1",
"next": "12.1.0",
"next-sanity-image": "^3.2.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-hot-toast": "^2.2.0",
"react-icons": "^4.3.1",
"stripe": "^8.209.0"
},
"devDependencies": {
"eslint": "^8.10.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-next": "^12.1.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.29.3",
"eslint-plugin-react-hooks": "^4.3.0"
}
}
import React, { createContext, useContext, useState, useEffect } from 'react';
import { toast } from 'react-hot-toast';
const Context = createContext();
export const StateContext = ({ children }) => {
const getLocalStorage = (name) => {
if (typeof window !== 'undefined') {
const storage = localStorage.getItem(name);
if (storage) return JSON.parse(localStorage.getItem(name));
if (name === 'cartItems') return [];
return 0;
}
};
const [showCart, setShowCart] = useState(false);
const [cartItems, setCartItems] = useState(getLocalStorage('cartItems'));
const [totalPrice, setTotalPrice] = useState(getLocalStorage('totalPrice'));
const [totalQuantities, setTotalQuantities] = useState(getLocalStorage('totalQuantities'));
const [qty, setQty] = useState(1);
let findProduct;
let index;
useEffect(() => {
localStorage.setItem('cartItems', JSON.stringify(cartItems));
localStorage.setItem('totalPrice', JSON.stringify(totalPrice));
localStorage.setItem('totalQuantities', JSON.stringify(totalQuantities));
}, [cartItems, totalPrice, totalQuantities]);
const onAdd = (product, quantity) => {
const checkProductInCart = cartItems.find(
(cartProduct) => cartProduct._id === product._id,
);
if (checkProductInCart) {
setTotalPrice(totalPrice + product.price * quantity);
setTotalQuantities(totalQuantities + quantity);
const updatedCartItems = cartItems.map((cartProduct) => {
if (cartProduct._id === product._id) {
return { ...cartProduct, quantity: cartProduct.quantity + quantity };
}
return cartProduct;
});
setCartItems(updatedCartItems);
toast.success(`${qty} ${product.name} added`);
} else {
setTotalPrice(totalPrice + product.price * quantity);
setTotalQuantities(totalQuantities + quantity);
// eslint-disable-next-line no-param-reassign
product.quantity = quantity;
setCartItems([...cartItems, { ...product }]);
toast.success(`${qty} ${product.name} added`);
}
};
const onRemove = (product) => {
findProduct = cartItems.find((item) => item._id === product._id);
const tempCart = cartItems.filter((item) => item._id !== product._id);
setTotalPrice(totalPrice - findProduct.price * findProduct.quantity);
setTotalQuantities(totalQuantities - findProduct.quantity);
setCartItems(tempCart);
};
const toggleCartItemQuantity = (id, value) => {
findProduct = cartItems.find((item) => item._id === id);
index = cartItems.findIndex((product) => product._id === id);
if (value === 'inc') {
findProduct.quantity += 1;
cartItems[index] = findProduct;
setTotalPrice(totalPrice + findProduct.price);
setTotalQuantities(totalQuantities + 1);
}
if (value === 'dec') {
if (findProduct.quantity > 1) {
findProduct.quantity -= 1;
cartItems[index] = findProduct;
setTotalPrice(totalPrice - findProduct.price);
setTotalQuantities(totalQuantities - 1);
}
}
};
const incQty = () => {
setQty((oldQty) => {
const tempQty = oldQty + 1;
return tempQty;
});
};
const decQty = () => {
setQty((oldQty) => {
let tempQty = oldQty - 1;
if (tempQty < 1) {
tempQty = 1;
}
return tempQty;
});
};
return (
<Context.Provider
// eslint-disable-next-line react/jsx-no-constructed-context-values
value={{
onAdd,
onRemove,
cartItems,
totalPrice,
totalQuantities,
setShowCart,
setCartItems,
setTotalPrice,
setTotalQuantities,
showCart,
incQty,
decQty,
qty,
toggleCartItemQuantity,
}}
>
{children}
</Context.Provider>
);
};
export const useStateContext = () => useContext(Context);
@aaldyy
Copy link

aaldyy commented Sep 15, 2022

thanksssss broo

@SamsonTimilehin
Copy link

Awesome!!! Thank you bro

@MauriceWebb
Copy link

This is great, thank you!

@urmil22
Copy link

urmil22 commented Nov 1, 2022

Great tutorial unfortunately I got some error even watched 3.34hours .. it saying Cannot destructure property 'image' of 'product' as it is null

when I clicked on herobanner and homebanner buttonText . if someone know the issue would be great to share with me thank you

I got the same issue, just add the product name same in Banner, for ex here bagpack, and compare it when you click on Banner, it should be like http://localhost:3000/product/bagpack.

Screenshot 2022-11-01 223006

@RyanEl-Annan
Copy link

ecommerce-error

having an issue for some reason

@vivekanand-vr
Copy link

I am struck at stripe section; the checkout button is showing redirecting.... IN console I am getting a warning _

 " Warning: Expected `onClick` listener to be a function, instead got a value of `string` type. "

Please help me out if possible, I don't know where I went wrong...

@vivekanand-vr
Copy link

Great tutorial unfortunately I got some error even watched 3.34hours .. it saying Cannot destructure property 'image' of 'product' as it is null
when I clicked on herobanner and homebanner buttonText . if someone know the issue would be great to share with me thank you

Make sure that in the Sanity CMS you have the same names in the product field for both Product and Banner documents, for example after seeing your message I tried checking it on my code and experienced the same error. Then I saw that in my Banner document the product was named 'headphones' and in the Product document it was named 'headphones-c', after making them both the same the issue was gone.

Basically make sure the Banner product links to a valid slug otherwise it won't work.

Hi please help me I am struck at checkout button, It's not redirecting me to payments page.

next-dev.js?3515:20

   Warning: Expected `onClick` listener to be a function, instead got a value of `string` type.

Showing this error.

@vivekanand-vr
Copy link

Please help me out I am getting this error
Failed to load resource: the server responded with a status of 400 (Bad Request) ...

@yskooo
Copy link

yskooo commented Nov 16, 2022

:)

@vivekanand-vr
Copy link

Did you guys deploy? Need help with the deployment. Error it is showing on Vercel.

Check the spelling on the environment variables, there is - instead of _ so make all _

@FrancoFrancis
Copy link

i need help, cant find the products and banner schemas I have created on my sanity desk

@KaiCodesWithGithub
Copy link

Getting error Parsing error: Cannot find module 'next/babel'
Please help!

@KingMark619
Copy link

Amazing work

@adilaben
Copy link

Thank you!

@MaxT6
Copy link

MaxT6 commented Feb 10, 2023

If anyone is encountering the error "module not found" relating to the import { Inter } from '@next/font/google' you can solve it by installing back "@next/font": "13.1.6", "next": "13.1.6" back into the dependencies and rerunning npm install --legacy-peer-deps terminal command, then restarting the web page. I tried just deleting the import on the index.js but that didn't solve it for me. If anyone else has a solution let me know!

@GurajBhoday
Copy link

error - ./pages/_app.js:1:0
Module not found: Can't resolve '@/styles/globals.css'
I keep getting that error before I even enter one line of code. Any idea how to resolve it.

@MaxT6
Copy link

MaxT6 commented Mar 17, 2023

error - ./pages/_app.js:1:0
Module not found: Can't resolve '@/styles/globals.css'
I keep getting that error before I even enter one line of code. Any idea how to resolve it.

Have you created the global.css file yet? Sounds like your app file is attempting to import the globals.css file but it either isn’t created or you didn’t import it correctly

@GurajBhoday
Copy link

error - ./pages/_app.js:1:0
Module not found: Can't resolve '@/styles/globals.css'
I keep getting that error before I even enter one line of code. Any idea how to resolve it.

Have you created the global.css file yet? Sounds like your app file is attempting to import the globals.css file but it either isn’t created or you didn’t import it correctly

Thank you, I managed to solve it, the issue was in the dependency part, I was copying his code so the different versions were throwing the error

@GurajBhoday
Copy link

Module parse failed: Unexpected token (1:7)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

export type Platform = 'browser' | 'node' | 'neutral';
| export type Format = 'iife' | 'cjs' | 'esm';
| export type Loader = 'base64' | 'binary' | 'copy' | 'css' | 'dataurl' | 'default' | 'empty' | 'file' | 'js' | 'json' | 'jsx' | 'text' | 'ts' | 'tsx';

This is another error I am getting

@StartingFrom101
Copy link

ecommerce-error

having an issue for some reason

try npx [email protected], version 13 of create-next-app breaks some stuff for me

@HamzaChbit
Copy link

Stripe routing. Next13 : app/api/stripe/route.js. is correct

@FrancoFrancis
Copy link

happy to be back here after a while :)

@zelda999
Copy link

zelda999 commented Sep 15, 2023

Thanks brother,
I change a little for StateContext file

const toggleCartItemQuantity = (id: string, value: string) => {
    foundProduct = cartItems.find((item) => item._id === id);
    index = cartItems.findIndex((product) => product._id === id);
    if (foundProduct && foundProduct.quantity !== undefined) {
      if (value === "inc") {
        foundProduct.quantity += 1;
        cartItems[index] = foundProduct;

        setCartItems([...cartItems]); // set again if use localstorage
        setTotalPrice(totalPrice + foundProduct.price);
        setTotalQuantities(totalQuantities + 1);
      } else if (value === "dec") {
        if (foundProduct.quantity > 1) {
          foundProduct.quantity -= 1;
          cartItems[index] = foundProduct;

          setCartItems([...cartItems]); // set again if use localstorage
          setTotalPrice(totalPrice - foundProduct.price);
          setTotalQuantities(totalQuantities - 1);
        }
      }
    }
  };

I have a problem when using localStorage and I found a way to resolve it. I want to share with everyone, I hope it will help somebody the same me

@FadyAdel04
Copy link

Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'length')

({totalQuantities} items)
20 |

21 | {(cartItems.length < 1 )(
| ^
22 |


23 |
24 |

Your shopping bag is empty

help please

@responsive-we
Copy link

responsive-we commented Oct 14, 2023

import React, { useRef } from 'react';
import Link from 'next/link';
import { AiOutlineMinus, AiOutlinePlus, AiOutlineLeft, AiOutlineShopping } from 'react-icons/ai';
import { TiDeleteOutline } from 'react-icons/ti';
import toast from 'react-hot-toast';

import { useStateContext } from '../context/StateContext';
import { urlFor } from '../lib/client';


const Cart = () => {
  const cartRef = useRef();
  const { totalPrice, totalQuantities, cartItems, setShowCart } = useStateContext();

  return (
    <div className="cart-wrapper" ref={cartRef}>
      <div className="cart-container">
        <button
        type="button"
        className="cart-heading"
        onClick={() => setShowCart(false)}>
          <AiOutlineLeft />
          <span className="heading">Your Cart</span>
          <span className="cart-num-items">({totalQuantities} items)</span>
        </button>

        {cartItems.length < 1 && (
          <div className="empty-cart">
            <AiOutlineShopping size={150} />
            <h3>Your shopping bag is empty</h3>
            <Link href="/">
              <button
                type="button"
                onClick={() => setShowCart(false)}
                className="btn"
              >
                Continue Shopping
              </button>
            </Link>
          </div>
        )}

        <div className="product-container">
          {cartItems.length >= 1 && cartItems.map((item) => (
            <div className="product" key={item._id}>
              <img src={urlFor(item?.image[0])} className="cart-product-image" />

            </div>
          ))}
        </div>
      </div>
    </div>
  )
}

export default Cart

I am getting an error saying :"Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading '0')"

Please help me ASAP!!
image

@programmer1402
Copy link

import React, { useRef } from 'react';
import Link from 'next/link';
import { AiOutlineMinus, AiOutlinePlus, AiOutlineLeft, AiOutlineShopping } from 'react-icons/ai';
import { TiDeleteOutline } from 'react-icons/ti';
import toast from 'react-hot-toast';

import { useStateContext } from '../context/StateContext';
import { urlFor } from '../lib/client';


const Cart = () => {
  const cartRef = useRef();
  const { totalPrice, totalQuantities, cartItems, setShowCart } = useStateContext();

  return (
    <div className="cart-wrapper" ref={cartRef}>
      <div className="cart-container">
        <button
        type="button"
        className="cart-heading"
        onClick={() => setShowCart(false)}>
          <AiOutlineLeft />
          <span className="heading">Your Cart</span>
          <span className="cart-num-items">({totalQuantities} items)</span>
        </button>

        {cartItems.length < 1 && (
          <div className="empty-cart">
            <AiOutlineShopping size={150} />
            <h3>Your shopping bag is empty</h3>
            <Link href="/">
              <button
                type="button"
                onClick={() => setShowCart(false)}
                className="btn"
              >
                Continue Shopping
              </button>
            </Link>
          </div>
        )}

        <div className="product-container">
          {cartItems.length >= 1 && cartItems.map((item) => (
            <div className="product" key={item._id}>
              <img src={urlFor(item?.image[0])} className="cart-product-image" />

            </div>
          ))}
        </div>
      </div>
    </div>
  )
}

export default Cart

I am getting an error saying :"Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading '0')"

Please help me ASAP!! image

could you check the cartItems, and it contains array image?

@responsive-we
Copy link

Thank you for your solution. There was some error in StateContext.js file

@Amir-gabr
Copy link

import React, { useRef } from 'react';
import Link from 'next/link';
import { AiOutlineMinus, AiOutlinePlus, AiOutlineLeft, AiOutlineShopping } from 'react-icons/ai';
import { TiDeleteOutline } from 'react-icons/ti';
import toast from 'react-hot-toast';

import { useStateContext } from '../context/StateContext';
import { urlFor } from '../lib/client';

const Cart = () => {
const cartRef = useRef();
const { totalPrice, totalQuantities, cartItems, setShowCart } = useStateContext();

return (



<button
type="button"
className="cart-heading"
onClick={() => setShowCart(false)}>

Your Cart
({totalQuantities} items)

    {cartItems.length < 1 && (
      <div className="empty-cart">
        <AiOutlineShopping size={150} />
        <h3>Your shopping bag is empty</h3>
        <Link href="/">
          <button
            type="button"
            onClick={() => setShowCart(false)}
            className="btn"
          >
            Continue Shopping
          </button>
        </Link>
      </div>
    )}

    <div className="product-container">
      {cartItems.length >= 1 && cartItems.map((item) => (
        <div className="product" key={item._id}>
          <img src={urlFor(item?.image[0])} className="cart-product-image" />

        </div>
      ))}
    </div>
  </div>
</div>

)
}

export default Cart
I am getting an error saying :"Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading '0')"
275152381-5f51063e-ac8a-4963-b03f-4602b6060b65
275152381-5f51063e-ac8a-4963-b03f-4602b6060b65

@responsive-we
Copy link

import React, { useRef } from 'react'; import Link from 'next/link'; import { AiOutlineMinus, AiOutlinePlus, AiOutlineLeft, AiOutlineShopping } from 'react-icons/ai'; import { TiDeleteOutline } from 'react-icons/ti'; import toast from 'react-hot-toast';

import { useStateContext } from '../context/StateContext'; import { urlFor } from '../lib/client';

const Cart = () => { const cartRef = useRef(); const { totalPrice, totalQuantities, cartItems, setShowCart } = useStateContext();

return (

<button
type="button"
className="cart-heading"
onClick={() => setShowCart(false)}>

Your Cart
({totalQuantities} items)

    {cartItems.length < 1 && (
      <div className="empty-cart">
        <AiOutlineShopping size={150} />
        <h3>Your shopping bag is empty</h3>
        <Link href="/">
          <button
            type="button"
            onClick={() => setShowCart(false)}
            className="btn"
          >
            Continue Shopping
          </button>
        </Link>
      </div>
    )}

    <div className="product-container">
      {cartItems.length >= 1 && cartItems.map((item) => (
        <div className="product" key={item._id}>
          <img src={urlFor(item?.image[0])} className="cart-product-image" />

        </div>
      ))}
    </div>
  </div>
</div>

) }

export default Cart I am getting an error saying :"Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading '0')" 275152381-5f51063e-ac8a-4963-b03f-4602b6060b65 275152381-5f51063e-ac8a-4963-b03f-4602b6060b65

You must see the output coming by logging the item param using console.log. And after getting the output you can debug it further or share it in this comment section.

@lambofil
Copy link

lambofil commented Apr 9, 2024

can somebody share all the command for installing all the dependencies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment