Skip to content

Commit

Permalink
Notification/Loading
Browse files Browse the repository at this point in the history
-Add Notification when user add to cart
-Add loading stage when loading from local storage
  • Loading branch information
AndreRimes committed Nov 21, 2023
1 parent 39536c8 commit 39eb3d2
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 37 deletions.
59 changes: 31 additions & 28 deletions app/Cart/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import { useCartProducts } from '../Domain/cartContext'
import Image from 'next/image';
import emptyCart from '../images/empty-cart.png'
import Link from 'next/link';
import Loading from '../components/loading';

export default function CartPage() {
const { isDarkMode } = useTheme();
const [subTotal, setSubTotal] = useState(0)
const [showModal, setShowModal] = useState(false)
const { cartProducts } = useCartProducts();
const { cartProducts, cartLoading } = useCartProducts();

useEffect(() => {
let newSubtotal = 0
Expand All @@ -30,35 +31,37 @@ export default function CartPage() {
<div className='h-24 w-[80vw] font-bold mt-16 flex flex-col items-center justify-center '>
<h1 className='text-3xl'>Shopping Cart</h1>
</div>
{cartProducts.length === 0 ?
<div className='flex flex-col items-center justify-center mt-10'>
<div className='h-40 w-40 rounded-full border-2 border-black flex items-center justify-center mb-4'>
<Image src={emptyCart} width={100} height={100} alt='Empty Cart Image'/>
</div>
<h1 className='text-3xl font-bold mb-2'>Your Cart is currently empty</h1>
<p className='text-lg'>Looks Like you haven&apos;t add anything to your cart yet</p>
<Link href='/' className=' hover:scale-110 mt-8 bg-ACMDARK w-44 h-10 flex items-center justify-center rounded-lg duration-200 transition-all ease-out'>Continue Shopping</Link>
</div>
: <>
<div>
{cartProducts && cartProducts.map((product) => {
return (
<CartProduct key={product.id} product={product} />
)
})}
</div>
<div className='w-10/12 flex flex-col items-end '>
<div className={`w-60 flex justify-between flex-row text-xl font-bold mb-4 text-ACMDARK`}>
<h1 className='' >SubTotal</h1>
<h1>${subTotal}</h1>
{cartLoading ? <Loading isRed={false} /> : (<>
{cartProducts.length === 0 ?
<div className='flex flex-col items-center justify-center mt-10'>
<div className='h-40 w-40 rounded-full border-2 border-black flex items-center justify-center mb-4'>
<Image src={emptyCart} width={100} height={100} alt='Empty Cart Image' />
</div>
<button
onClick={() => setShowModal(true)}
className='hover:scale-110 text-lg duration-200 mb-10 transition-all ease-out bg-ACMDARK w-60 h-10 pt-1 pb-1 rounded-lg text-white' >
Checkout
</button>
<h1 className='text-3xl font-bold mb-2'>Your Cart is currently empty</h1>
<p className='text-lg'>Looks Like you haven&apos;t add anything to your cart yet</p>
<Link href='/' className=' hover:scale-110 mt-8 bg-ACMDARK w-44 h-10 flex items-center justify-center rounded-lg duration-200 transition-all ease-out'>Continue Shopping</Link>
</div>
</>}
: <>
<div>
{cartProducts && cartProducts.map((product) => {
return (
<CartProduct key={product.id} product={product} />
)
})}
</div>
<div className='w-10/12 flex flex-col items-end '>
<div className={`w-60 flex justify-between flex-row text-xl font-bold mb-4 text-ACMDARK`}>
<h1 className='' >SubTotal</h1>
<h1>${subTotal}</h1>
</div>
<button
onClick={() => setShowModal(true)}
className='hover:scale-110 text-lg duration-200 mb-10 transition-all ease-out bg-ACMDARK w-60 h-10 pt-1 pb-1 rounded-lg text-white' >
Checkout
</button>
</div>
</>}
</>)}
<ModalCheckOut products={cartProducts} subTotal={subTotal} showModal={showModal} setShowModal={setShowModal} />
</div>
</div>
Expand Down
4 changes: 3 additions & 1 deletion app/Domain/cartContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const CartContext = createContext();

export function CartContextProvider({ children }) {
const [cartProducts, setCartProducts] = useState([]);
const [cartLoading , setCarLoading] = useState(true)

const saveStateToLocalStorage = (state) => {
const serializedState = JSON.stringify(state);
Expand All @@ -22,6 +23,7 @@ export function CartContextProvider({ children }) {
useEffect(() => {
const loadedCartState = loadStateFromLocalStorage();
setCartProducts(loadedCartState);
setCarLoading(false)
}, []);

useEffect(() => {
Expand Down Expand Up @@ -82,7 +84,7 @@ export function CartContextProvider({ children }) {
}

return (
<CartContext.Provider value={{ cartProducts, addToCart, removeOne, removeAll, isInCart, clearCart}}>
<CartContext.Provider value={{ cartProducts, addToCart, removeOne, removeAll, isInCart, clearCart,cartLoading}}>
{children}
</CartContext.Provider>
);
Expand Down
11 changes: 6 additions & 5 deletions app/components/ProductDescription.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState } from "react";
import { useCartProducts } from "../Domain/cartContext";
import { useRouter } from "next/navigation";

export default function ProductDescription({product ,title, description, quantity, price }) {
export default function ProductDescription({product ,title, description, quantity, price,setShowNotification }) {
const { addToCart } = useCartProducts();
const [selectedQuantity, setSelectedQuantity] = useState(0);
const router = useRouter();
Expand All @@ -23,6 +23,7 @@ export default function ProductDescription({product ,title, description, quantit

function handleAddToCart() {
addToCart(product,selectedQuantity)
setShowNotification(true)
}


Expand All @@ -32,16 +33,16 @@ export default function ProductDescription({product ,title, description, quantit
}

return (
<div className="flex w-[55%] h-[65%] flex-col items-center justify-evenly">
<div className="w-7/12 h-4/6 bg-white flex flex-col items-center justify-center rounded-lg">
<div className="flex w-[55%] h-[65%] flex-col items-center justify-evenly ">
<div className="w-7/12 h-4/6 bg-white flex flex-col items-center justify-center rounded-lg ">
<div className="w-11/12 h-10">
<h1 className="text-2xl font-bold">{title}</h1>
</div>
<div className="w-11/12 h-0 border border-black"></div>
<div className="w-11/12 h-8">
<h2 className="text-xl font-bold">${price}</h2>
</div>
<p className="w-11/12 max-h-56 overflow-hidden">{description}</p>
<p className="w-11/12 h-56 max-h-56 overflow-hidden py-2">{description}</p>
</div>
<div className="w-7/12 flex flex-row items-center justify-between text-lg font-semibold ">
<button
Expand All @@ -52,7 +53,7 @@ export default function ProductDescription({product ,title, description, quantit
</button>
<select
name="Qty: "
className="w-1/3 h-10 rounded-lg bg-ACMDARK text-white border-none px-2"
className="w-1/3 h-10 rounded-lg bg-ACMDARK text-white border-none px-2 cursor-pointer"
onChange={(e) => setSelectedQuantity(parseInt(e.target.value))}
>
{quantityOptions}
Expand Down
2 changes: 1 addition & 1 deletion app/components/cartProduct.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function CartProduct({ product }) {
))}
</div>

<div className="h-5/6 flex flex-col">
<div className="h-5/6 flex flex-col 2xl:mr-0 mr-10">
<div className="flex flex-row font-bold mb-10">
<h2 className="text-2xl mr-14">${price}</h2>
<h2 onClick={() => removeAll(id)} onMouseLeave={(e) => handleLeave(e)} onMouseEnter={(e) => handleEnter(e)} className="text-2xl duration-200 transition-all ease-in cursor-pointer">X</h2>
Expand Down
33 changes: 33 additions & 0 deletions app/components/notification.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useState, useEffect } from "react";

export default function Notification({ setShowNotification }) {
const [progress, setProgress] = useState(100);

useEffect(() => {
const interval = setInterval(() => {
setProgress((prevProgress) => (prevProgress - 1));
}, 60);

}, []);

useEffect(() => {
if (progress <= 0) {
setShowNotification(false);
}
}, [progress, setShowNotification]);

return (
<div className="animate-notification absolute w-1/4 h-[80px] translate-y-[-30vh] flex items-center justify-center flex-col bg-ACMDARK text-white rounded-lg">
<div className="w-11/12 text-xl font-semibold">
<h1 className="cursor-pointer" onClick={() => setShowNotification(false)}>X</h1>
</div>
<h1 className="text-lg font-semibold mb-2">Product Add to the cart effectively</h1>
<div className="w-[95%] h-10 bg-black mb-2 ">
<div
className={`h-full bg-white `}
style={{ width: `${progress}%` }}
/>
</div>
</div>
);
}
5 changes: 4 additions & 1 deletion app/products/[id]/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { useTheme } from "../../Domain/ThemeContext";
import { useProducts } from "@/app/Domain/ProductContext";
import Image from "next/image";
import ProductDescription from "@/app/components/ProductDescription";
import Notification from "@/app/components/notification";

export default function product({ params }) {
const { isDarkMode } = useTheme();

Check failure on line 10 in app/products/[id]/page.jsx

View workflow job for this annotation

GitHub Actions / ESLint

app/products/[id]/page.jsx#L10

React Hook "useTheme" is called in function "product" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use" (react-hooks/rules-of-hooks)
const { products, getURL } = useProducts();

Check failure on line 11 in app/products/[id]/page.jsx

View workflow job for this annotation

GitHub Actions / ESLint

app/products/[id]/page.jsx#L11

React Hook "useProducts" is called in function "product" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use" (react-hooks/rules-of-hooks)
const [product, setProduct] = useState({})

Check failure on line 12 in app/products/[id]/page.jsx

View workflow job for this annotation

GitHub Actions / ESLint

app/products/[id]/page.jsx#L12

React Hook "useState" is called in function "product" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use" (react-hooks/rules-of-hooks)
const [showNotification,setShowNotification] = useState(false)

Check failure on line 13 in app/products/[id]/page.jsx

View workflow job for this annotation

GitHub Actions / ESLint

app/products/[id]/page.jsx#L13

React Hook "useState" is called in function "product" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use" (react-hooks/rules-of-hooks)


useEffect(() => {

Check failure on line 16 in app/products/[id]/page.jsx

View workflow job for this annotation

GitHub Actions / ESLint

app/products/[id]/page.jsx#L16

React Hook "useEffect" is called in function "product" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use" (react-hooks/rules-of-hooks)

Check warning on line 16 in app/products/[id]/page.jsx

View workflow job for this annotation

GitHub Actions / ESLint

app/products/[id]/page.jsx#L16

React Hook useEffect contains a call to 'setProduct'. Without a list of dependencies, this can lead to an infinite chain of updates. To fix this, pass [products, params.id] as a second argument to the useEffect Hook (react-hooks/exhaustive-deps)
Expand All @@ -22,9 +24,10 @@ export default function product({ params }) {
return (
<>
<div className={`${isDarkMode ? 'bg-ACMPrimary' : 'bg-ACMBLUE'} flex flex-row items-center justify-center text-ACMDARK h-screen bg-cover bg-center w-full`}>
{showNotification && <Notification setShowNotification={setShowNotification}/>}
<div className="w-full h-full flex flex-row items-center justify-center mt-28">
<Image src={getURL(product)} width={400} height={400} />

Check warning on line 29 in app/products/[id]/page.jsx

View workflow job for this annotation

GitHub Actions / ESLint

app/products/[id]/page.jsx#L29

Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images (jsx-a11y/alt-text)
<ProductDescription product={product} title={product?.title} price={product?.price} quantity={product?.quantity} description={product?.description} />
<ProductDescription setShowNotification={setShowNotification} product={product} title={product?.title} price={product?.price} quantity={product?.quantity} description={product?.description} />
</div>
</div>

Expand Down
7 changes: 6 additions & 1 deletion tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,14 @@ module.exports = {
typewriter: 'typewriter 2s steps(44) 1s 1 normal both, blinkTextCursor 500ms steps(44) 5 normal',
dropTop: 'dropTop 0.2s ease-in',
slideIn: 'slideIn 0.3s ease-out',
loading: 'loading 2s infinite ease-in-out'
loading: 'loading 2s infinite ease-in-out',
notification:'notification 0.3s ease-out'
},
keyframes:{
notification:{
'0%':{transform:'translateY(-120vh)',opacity:'0'},
'100%':{transform:'translateY(-30vh)',opacity:'1'}
},
dropTop:{
'0%': {transform: 'translate(50%,50%)', opacity:'0',scale:'0.5' },
'100%': {transform:'translate(0%,0%)',opacity:'1',scale:'1'}
Expand Down

0 comments on commit 39eb3d2

Please sign in to comment.