diff options
| author | Rafi Zadanly <rafizadanly@gmail.com> | 2022-12-14 17:48:03 +0700 |
|---|---|---|
| committer | Rafi Zadanly <rafizadanly@gmail.com> | 2022-12-14 17:48:03 +0700 |
| commit | bd4008ac5c2a22c1d99239ba0691cfb8ef0e9aea (patch) | |
| tree | c2f1289cfaa68ba5154e695f26d80278f42208f1 /src | |
| parent | 4e2b85a16b032df07686fd044ba9183afceb8b11 (diff) | |
add to cart, cart page, change cart item quantity
Diffstat (limited to 'src')
| -rw-r--r-- | src/helpers/cart.js | 39 | ||||
| -rw-r--r-- | src/icons/minus.svg | 3 | ||||
| -rw-r--r-- | src/icons/plus.svg | 4 | ||||
| -rw-r--r-- | src/pages/shop/brands/[slug].js | 4 | ||||
| -rw-r--r-- | src/pages/shop/cart.js | 167 | ||||
| -rw-r--r-- | src/pages/shop/product/[slug].js | 4 |
6 files changed, 163 insertions, 58 deletions
diff --git a/src/helpers/cart.js b/src/helpers/cart.js index 07e47324..8712c03a 100644 --- a/src/helpers/cart.js +++ b/src/helpers/cart.js @@ -1,7 +1,7 @@ const getCart = () => { const cart = localStorage.getItem('cart'); if (cart) return JSON.parse(cart); - return []; + return {}; } const setCart = (cart) => { @@ -9,18 +9,18 @@ const setCart = (cart) => { return true; } -const getItemIndex = (product_id) => { - const cart = getCart(); - return cart.findIndex((item) => item.product_id == product_id); +const getItemCart = (product_id) => { + let cart = getCart(); + return cart[product_id]; } -const addToCart = (product_id, quantity) => { +const createOrUpdateItemCart = (product_id, quantity) => { let cart = getCart(); - let itemIndexByProductId = getItemIndex(product_id); - if (itemIndexByProductId > -1) { - updateItemCart(product_id, quantity); + let isFoundInCart = cart[product_id]; + if (isFoundInCart) { + cart[product_id].quantity = quantity; } else { - cart.push({ product_id, quantity }); + cart[product_id] = { product_id, quantity }; } setCart(cart); return true; @@ -28,27 +28,14 @@ const addToCart = (product_id, quantity) => { const deleteItemCart = (product_id) => { let cart = getCart(); - let itemIndexByProductId = getItemIndex(product_id); - if (itemIndexByProductId > -1) { - cart.splice(itemIndexByProductId, 1) - } - setCart(cart); - return true; -} - -const updateItemCart = (product_id, quantity) => { - let cart = getCart(); - let itemIndexByProductId = getItemIndex(product_id); - if (itemIndexByProductId > -1) { - cart[itemIndexByProductId].quantity += quantity; - } + delete cart[product_id] setCart(cart); return true; } export { getCart, - addToCart, - deleteItemCart, - updateItemCart + getItemCart, + createOrUpdateItemCart, + deleteItemCart }
\ No newline at end of file diff --git a/src/icons/minus.svg b/src/icons/minus.svg new file mode 100644 index 00000000..12a10199 --- /dev/null +++ b/src/icons/minus.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-minus"> + <line x1="5" y1="12" x2="19" y2="12"></line> +</svg>
\ No newline at end of file diff --git a/src/icons/plus.svg b/src/icons/plus.svg new file mode 100644 index 00000000..2923c684 --- /dev/null +++ b/src/icons/plus.svg @@ -0,0 +1,4 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus"> + <line x1="12" y1="5" x2="12" y2="19"></line> + <line x1="5" y1="12" x2="19" y2="12"></line> +</svg>
\ No newline at end of file diff --git a/src/pages/shop/brands/[slug].js b/src/pages/shop/brands/[slug].js index 320c4454..b04d2715 100644 --- a/src/pages/shop/brands/[slug].js +++ b/src/pages/shop/brands/[slug].js @@ -88,8 +88,8 @@ export default function BrandDetail({ <button className="btn-light py-2 flex items-center gap-x-2 mb-2" onClick={() => setActiveFilter(true)}> <FilterIcon className="w-4 h-4" /> <span>Filter</span> </button> - <h1>Produk</h1> - <div className="text-caption mb-4"> + <h1 className="mb-2">Produk</h1> + <div className="text-caption-1 mb-4"> {productFound > 0 ? ( <> Menampilkan diff --git a/src/pages/shop/cart.js b/src/pages/shop/cart.js index 635d4efd..5e7ff822 100644 --- a/src/pages/shop/cart.js +++ b/src/pages/shop/cart.js @@ -1,49 +1,160 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import Header from "../../components/Header"; import Layout from "../../components/Layout"; import Link from "../../components/Link"; -import { getCart } from "../../helpers/cart"; +import { createOrUpdateItemCart, deleteItemCart, getCart, getItemCart } from "../../helpers/cart"; import ChevronLeftIcon from "../../icons/chevron-left.svg"; +import MinusIcon from "../../icons/minus.svg"; +import PlusIcon from "../../icons/plus.svg"; +import { LazyLoadImage } from "react-lazy-load-image-component"; + +import 'react-lazy-load-image-component/src/effects/blur.css'; +import apiOdoo from "../../helpers/apiOdoo"; +import currencyFormat from "../../helpers/currencyFormat"; export default function Cart() { + const [products, setProducts] = useState([]); + + const getProducts = async () => { + let cart = getCart(); + let productIds = Object.keys(cart); + if (productIds.length > 0) { + productIds = productIds.join(','); + let dataProducts = await apiOdoo('GET', `/api/v1/product_variant/${productIds}`); + dataProducts = dataProducts.map((product) => ({ + ...product, + quantity: cart[product.id].quantity + })); + setProducts(dataProducts); + } + } + useEffect(() => { - console.log(getCart()); - }) + getProducts(); + }, []); + + const updateCart = (productId, quantity) => { + let productIndexToUpdate = products.findIndex((product) => product.id == productId); + if (quantity != '') createOrUpdateItemCart(productId, quantity); + setProducts((products) => { + products[productIndexToUpdate].quantity = quantity; + return [...products]; + }); + }; + + const blurQuantity = (productId, quantity) => { + quantity = quantity == ('' || 0) ? 1 : parseInt(quantity); + updateCart(productId, quantity); + }; + + const updateQuantity = (productId, quantity) => { + quantity = quantity == '' ? '' : parseInt(quantity); + updateCart(productId, quantity); + }; + + const plusQuantity = (productId) => { + let productIndexToUpdate = products.findIndex((product) => product.id == productId); + let quantity = products[productIndexToUpdate].quantity + 1; + updateCart(productId, quantity); + } + + const minusQuantity = (productId) => { + let productIndexToUpdate = products.findIndex((product) => product.id == productId); + let quantity = products[productIndexToUpdate].quantity - 1; + if (quantity <= 0) { + deleteItemCart(productId); + setProducts((products) => { + products.splice(productIndexToUpdate, 1); + return [...products]; + }); + } else { + updateCart(productId, quantity); + } + } + return ( <> <Header title={`Keranjang Belanja - Indoteknik`}/> <Layout> - <div className="p-4"> - {/* Progress Bar */} - <div className="bg-gray_r-2 flex gap-x-2 p-4 rounded-md mb-4"> - <div className="flex gap-x-2 items-center"> - <div className="bg-yellow_r-9 leading-none p-2 rounded-full w-7 text-center text-gray_r-12 text-caption-2">1</div> - <p className="font-medium text-gray_r-12 text-caption-2">Keranjang</p> - </div> - <div className="flex-1 flex items-center"> - <div className="h-0.5 w-full bg-gray_r-7"></div> - </div> - <div className="flex gap-x-2 items-center"> - <div className="bg-gray_r-3 leading-none p-2 rounded-full w-7 text-center text-gray_r-11 text-caption-2">2</div> - <p className="font-medium text-gray_r-11 text-caption-2">Pembayaran</p> - </div> - <div className="flex-1 flex items-center"> - <div className="h-0.5 w-full bg-gray_r-7"></div> - </div> - <div className="flex gap-x-2 items-center"> - <div className="bg-gray_r-3 leading-none p-2 rounded-full w-7 text-center text-gray_r-11 text-caption-2">3</div> - <p className="font-medium text-gray_r-11 text-caption-2">Selesai</p> - </div> + {/* jsx-start: Progress Bar */} + <div className="bg-gray_r-2 flex gap-x-2 p-4 rounded-md"> + <div className="flex gap-x-2 items-center"> + <div className="bg-yellow_r-9 leading-none p-2 rounded-full w-7 text-center text-gray_r-12 text-caption-2">1</div> + <p className="font-medium text-gray_r-12 text-caption-2">Keranjang</p> + </div> + <div className="flex-1 flex items-center"> + <div className="h-0.5 w-full bg-gray_r-7"></div> + </div> + <div className="flex gap-x-2 items-center"> + <div className="bg-gray_r-3 leading-none p-2 rounded-full w-7 text-center text-gray_r-11 text-caption-2">2</div> + <p className="font-medium text-gray_r-11 text-caption-2">Pembayaran</p> </div> - {/* [End] Progress Bar */} - {/* Title */} - <div className="flex gap-x-2"> + <div className="flex-1 flex items-center"> + <div className="h-0.5 w-full bg-gray_r-7"></div> + </div> + <div className="flex gap-x-2 items-center"> + <div className="bg-gray_r-3 leading-none p-2 rounded-full w-7 text-center text-gray_r-11 text-caption-2">3</div> + <p className="font-medium text-gray_r-11 text-caption-2">Selesai</p> + </div> + </div> + {/* [End] Progress Bar */} + <div className="p-4"> + + {/* [Start] Title */} + <div className="flex gap-x-2 mb-8"> <Link href="/" className="pr-2"> <ChevronLeftIcon className="w-6 stroke-gray_r-12"/> </Link> <h1>Keranjang Saya</h1> </div> {/* [End] Title */} + + {/* [Start] Product List */} + <div className="flex flex-col gap-y-6"> + {products.map((product, index) => ( + <div className="flex gap-x-3" key={index}> + <div className="w-4/12"> + <LazyLoadImage effect="blur" src={product.parent.image ? product.parent.image : '/images/noimage.jpeg'} alt={product.parent.name} className="object-contain object-center border border-gray_r-6 h-32 w-full rounded-md" /> + </div> + <div className="w-8/12 flex flex-col"> + <Link href="/" className="product-card__title wrap-line-ellipsis-2"> + {product.parent.name} + </Link> + <p className="text-caption-1 text-gray_r-11 mt-1">{product.code ? product.code : '-'}</p> + <div className="flex flex-wrap gap-x-1 items-center mb-2 mt-auto"> + <p className="text-caption-1 text-gray_r-12">{currencyFormat(product.price.price_discount)}</p> + {product.price.discount_percentage > 0 ? ( + <> + <span className="badge-red">{product.price.discount_percentage}%</span> + <p className="text-caption-2 text-gray_r-11 line-through">{currencyFormat(product.price.price)}</p> + </> + ) : ''} + + </div> + <div className="flex items-center"> + <p className="mr-auto text-caption-1 text-gray_r-12 font-bold">{currencyFormat(product.quantity * product.price.price_discount)}</p> + <div className="flex gap-x-2"> + <button className="btn-light p-1 rounded-full" onClick={() => minusQuantity(product.id)}> + <MinusIcon className="stroke-gray_r-12 w-3"/> + </button> + <input + type="number" + className="bg-transparent border-none w-4 text-center outline-none" + onBlur={(e) => blurQuantity(product.id, e.target.value)} + onChange={(e) => updateQuantity(product.id, e.target.value)} + value={product.quantity} + /> + <button className="btn-light p-1 rounded-full" onClick={() => plusQuantity(product.id)}> + <PlusIcon className="stroke-gray_r-12 w-3"/> + </button> + </div> + </div> + </div> + </div> + ))} + </div> + {/* [End] Product List */} + </div> </Layout> </> diff --git a/src/pages/shop/product/[slug].js b/src/pages/shop/product/[slug].js index e44cfeca..cabda175 100644 --- a/src/pages/shop/product/[slug].js +++ b/src/pages/shop/product/[slug].js @@ -9,7 +9,7 @@ import { LazyLoadImage } from "react-lazy-load-image-component"; import "react-lazy-load-image-component/src/effects/blur.css"; import ProductSlider from "../../../components/product/ProductSlider"; import Layout from "../../../components/Layout"; -import { addToCart } from "../../../helpers/cart"; +import { createOrUpdateItemCart } from "../../../helpers/cart"; export async function getServerSideProps( context ) { const { slug } = context.query; @@ -83,7 +83,7 @@ export default function ProductDetail({ product }) { let addItemToCart = () => { if (quantity > 0) { - addToCart(activeVariant.id, parseInt(quantity)); + createOrUpdateItemCart(activeVariant.id, parseInt(quantity)); } return true; } |
