Skip to content

Commit

Permalink
Merge pull request #62 from acm-uic/ProductDescription
Browse files Browse the repository at this point in the history
Product description
  • Loading branch information
Ajknight121 authored Jan 22, 2024
2 parents 92ba986 + 3caa904 commit 5e33eb1
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 63 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
10 changes: 8 additions & 2 deletions app/Domain/ProductContext.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import getProducts from './getProducts';
import React, { createContext, useContext, useState, useEffect } from 'react';

import pb from './pocketbase'
const ProductContext = createContext();

export const ProductProvider = ({ children }) => {
Expand All @@ -16,8 +16,14 @@ export const ProductProvider = ({ children }) => {
fetchProducts();
}, []);


function getURL(product) {
return pb.files.getUrl(product, product?.img);
}


return (
<ProductContext.Provider value={{ products }}>
<ProductContext.Provider value={{ products, getURL}}>
{children}
</ProductContext.Provider>
);
Expand Down
10 changes: 6 additions & 4 deletions 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 All @@ -30,14 +32,14 @@ export function CartContextProvider({ children }) {
}
}, [cartProducts]);

const addToCart = (product) => {
const addToCart = (product,n) => {
setCartProducts((currentItems) => {
if (currentItems.find((item) => item.id === product.id) == null) {
return [...currentItems, { ...product, cartQuantity: 1 }];
return [...currentItems, { ...product, cartQuantity: n }];
} else {
return currentItems.map((item) => {
if (item.id === product.id) {
return { ...item, cartQuantity: item.cartQuantity + 1 };
return { ...item, cartQuantity: item.cartQuantity + n };
} else {
return item;
}
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
62 changes: 62 additions & 0 deletions app/components/ProductDescription.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useCartProducts } from "../Domain/cartContext";
import { useRouter } from "next/navigation";

export default function ProductDescription({product ,title, description, quantity, price,setShowNotification,setSelectedQuantity,selectedQuantity }) {
const { addToCart } = useCartProducts();
const router = useRouter();

const quantityOptions = [];
for (let i = 1; i <= quantity; i++) {
{console.log(i)}
quantityOptions.push(
<option key={i} value={i}>
Qty: {i}
</option>
);
}

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


function handleBuy(){
addToCart(product,selectedQuantity)
router.push('/Cart')
}

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="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 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
onClick={handleAddToCart}
className="w-3/5 bg-white h-10 rounded-xl border-[1.5px] border-black hover:scale-110 transition-all duration-300 ease-out"
>
Add to Cart
</button>
<select
name="Qty: "
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))}
>
{console.log(quantityOptions)}
{quantityOptions}
</select>
</div>
<button onClick={()=>handleBuy()} className="w-7/12 h-10 text-xl font-semibold rounded-xl bg-ACMDARK text-white hover:scale-110 transition-all duration-300 ease-out ">
Buy Now
</button>
</div>
);
}
7 changes: 3 additions & 4 deletions app/components/cartProduct.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,18 @@ 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>
<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>
</div>

<div className="grid grid-cols-3 divide-x text-align text-lg " >
<div onClick={() => removeOne(id)} onMouseLeave={(e) => handleLeave(e)} onMouseEnter={(e) => handleEnter(e)} style={{ border: '1px solid black' }} className=" duration-200 transition-all ease-in flex items-center justify-center rounded-tl-lg rounded-bl-lg cursor-pointer font-bold">-</div>
<div style={{ border: '1px solid black' }} className=" flex items-center justify-center font-bold">{cartQuantity}</div>
<div onClick={() => addToCart(product)} onMouseLeave={(e) => handleLeave(e)} onMouseEnter={(e) => handleEnter(e)} style={{ border: '1px solid black' }} className=" duration-200 transition-all ease-in flex items-center justify-center rounded-tr-lg rounded-br-lg font-bold cursor-pointer">+</div>
<div onClick={() => addToCart(product,1)} onMouseLeave={(e) => handleLeave(e)} onMouseEnter={(e) => handleEnter(e)} style={{ border: '1px solid black' }} className=" duration-200 transition-all ease-in flex items-center justify-center rounded-tr-lg rounded-br-lg font-bold cursor-pointer">+</div>
</div>
</div>

</div >
)

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({selectedQuantity, setShowNotification,title}) {
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">{title} x{selectedQuantity} add to the cart</h1>
<div className="w-[95%] h-10 bg-black mb-2 ">
<div
className={`h-full bg-white `}
style={{ width: `${progress}%` }}
/>
</div>
</div>
);
}
12 changes: 6 additions & 6 deletions app/components/product.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@ import Link from "next/link";
import cartNotFull from '../images/cartNotFull.png'
import cartFull from '../images/cartFull.png'
import { useCartProducts } from "../Domain/cartContext";
import pb from "../Domain/pocketbase";

import { useProducts } from "../Domain/ProductContext";

export default function Product({ product, isDarkMode }) {
const [hovered, setHovered] = useState(false);
const { id, title, price } = product
const { cartProducts, removeAll, addToCart, isInCart } = useCartProducts();
let imgUrl = pb.files.getUrl(product, product.img)
const {removeAll, addToCart, isInCart } = useCartProducts();
const { getURL } = useProducts();
let imgUrl = getURL(product)

function handleClick(e, product) {
e.preventDefault();
if (isInCart(id)) {
removeAll(id);
} else {
addToCart(product);
addToCart(product,1);
}
}


return (
<Link href={`products/${id}`}>
<div
Expand Down
13 changes: 5 additions & 8 deletions app/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,23 @@ import { useState, useRef, useEffect } from "react";
import { useTheme } from "./Domain/ThemeContext";


import { ProductProvider } from "./Domain/ProductContext";

export default function Home() {
const { isDarkMode } = useTheme();
const productListRef = useRef([]);
const [productList, setProductList] = useState([])



const scrollToProductList = () => { //Scroll \\\\
productList.current.scrollIntoView({ behavior: "smooth" });
};


return (

return (
<div className="w-full h-full text-white" >
<HeroScreen scrollToProductList={scrollToProductList} isDarkMode={isDarkMode}/>
<ProductProvider>
<ProductList productList={productList} isDarkMode={isDarkMode} />
</ProductProvider>
<HeroScreen scrollToProductList={scrollToProductList} isDarkMode={isDarkMode} />
<ProductList productList={productList} isDarkMode={isDarkMode} />
</div>

);
Expand Down
10 changes: 7 additions & 3 deletions app/pageLayout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
import React from 'react';
import { ThemeProvider } from './Domain/ThemeContext';
import { CartContextProvider } from './Domain/cartContext';
import { ProductProvider } from "./Domain/ProductContext";


export default function PageLayout({ children }) {
return (
<ThemeProvider>
<CartContextProvider>
{children}
</CartContextProvider>
<ProductProvider>
<CartContextProvider>
{children}
</CartContextProvider>
</ProductProvider>
</ThemeProvider>
)
}
42 changes: 35 additions & 7 deletions app/products/[id]/page.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,35 @@
export default function product(){
return(
<div>
<h1>Product Page</h1>
</div>
)
}
"use client"
import { useEffect, useState } from "react";
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();
const { products, getURL } = useProducts();
const [product, setProduct] = useState({})
const [showNotification,setShowNotification] = useState(false)
const [selectedQuantity, setSelectedQuantity] = useState(1);


useEffect(() => {
const newProduct = products.filter((p) => p.id == params.id);
setProduct(newProduct[0]);
}, [products, params.id]);


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 title={product?.title} selectedQuantity={selectedQuantity} 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} alt={`${product?.title} Image`} />
<ProductDescription selectedQuantity={selectedQuantity} setSelectedQuantity={setSelectedQuantity} setShowNotification={setShowNotification} product={product} title={product?.title} price={product?.price} quantity={product?.quantity} description={product?.description} />
</div>
</div>

</>
);
}
Loading

0 comments on commit 5e33eb1

Please sign in to comment.