summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-02-20 10:49:35 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-02-20 10:49:35 +0700
commitd22df6bd30b8ed4bcfa938dcbbedc5fc376c2304 (patch)
tree8d86213da671f07a57f78bd5d6ac0cce80ffe970
parent71ca8757d549c62e7b2925793689815f4ab771ad (diff)
cart refactor
-rw-r--r--src/core/components/elements/Appbar/Appbar.jsx2
-rw-r--r--src/core/utils/cart.js4
-rw-r--r--src/lib/cart/components/Cart.jsx200
-rw-r--r--src/lib/cart/hooks/useCart.js4
-rw-r--r--src/lib/product/components/Product.jsx8
5 files changed, 199 insertions, 19 deletions
diff --git a/src/core/components/elements/Appbar/Appbar.jsx b/src/core/components/elements/Appbar/Appbar.jsx
index 0fe087d3..2a19ec6c 100644
--- a/src/core/components/elements/Appbar/Appbar.jsx
+++ b/src/core/components/elements/Appbar/Appbar.jsx
@@ -6,7 +6,7 @@ const AppBar = ({ title }) => {
const router = useRouter()
return (
- <nav className="sticky top-0 z-50 bg-white shadow flex justify-between">
+ <nav className="sticky top-0 z-50 bg-white border-b border-gray_r-6 flex justify-between">
<div className="flex items-center">
<button type="button" className="p-4" onClick={() => router.back()}>
<ChevronLeftIcon className="w-6 stroke-2" />
diff --git a/src/core/utils/cart.js b/src/core/utils/cart.js
index 928d2ad1..52e157f2 100644
--- a/src/core/utils/cart.js
+++ b/src/core/utils/cart.js
@@ -18,7 +18,7 @@ const getItemCart = ({ productId }) => {
return cart[productId]
}
-const addItemCart = ({ productId, quantity, selected = false }) => {
+const updateItemCart = ({ productId, quantity, selected = false }) => {
let cart = getCart()
quantity = parseInt(quantity)
cart[productId] = { productId, quantity, selected }
@@ -36,6 +36,6 @@ const deleteItemCart = ({ productId }) => {
export {
getCart,
getItemCart,
- addItemCart,
+ updateItemCart,
deleteItemCart
} \ No newline at end of file
diff --git a/src/lib/cart/components/Cart.jsx b/src/lib/cart/components/Cart.jsx
index 5f9ae1c0..3dd54429 100644
--- a/src/lib/cart/components/Cart.jsx
+++ b/src/lib/cart/components/Cart.jsx
@@ -1,28 +1,208 @@
import Link from "@/core/components/elements/Link/Link"
import useCart from "../hooks/useCart"
import Image from "@/core/components/elements/Image/Image"
+import currencyFormat from "@/core/utils/currencyFormat"
+import { useEffect, useState } from "react"
+import { getItemCart, updateItemCart } from "@/core/utils/cart"
+import { CheckIcon, RectangleGroupIcon } from "@heroicons/react/24/outline"
+import { createSlug } from "@/core/utils/slug"
+import { useRouter } from "next/router"
const Cart = () => {
- const { cart } = useCart()
+ const router = useRouter()
+ const [ products, setProducts ] = useState(null)
+ const { cart } = useCart({ enabled: !products })
+
+ const [ totalPriceBeforeTax, setTotalPriceBeforeTax ] = useState(0)
+ const [ totalTaxAmount, setTotalTaxAmount ] = useState(0)
+ const [ totalDiscountAmount, setTotalDiscountAmount ] = useState(0)
+
+ useEffect(() => {
+ if (cart.data && !products) {
+ const productsWithQuantity = cart.data.map((product) => {
+ const productInCart = getItemCart({ productId: product.id })
+ if (!productInCart) return
+ return {
+ ...product,
+ quantity: productInCart.quantity,
+ selected: productInCart.selected
+ }
+ })
+ setProducts(productsWithQuantity)
+ }
+ }, [cart, products])
+
+ useEffect(() => {
+ if (!products) return
+
+ let calculateTotalPriceBeforeTax = 0
+ let calculateTotalTaxAmount = 0
+ let calculateTotalDiscountAmount = 0
+ for (const product of products) {
+ if (product.quantity == '') continue
+ updateItemCart({
+ productId: product.id,
+ quantity: product.quantity,
+ selected: product.selected
+ })
+
+ if (!product.selected) continue
+ let priceBeforeTax = product.price.price / 1.11
+ calculateTotalPriceBeforeTax += priceBeforeTax * product.quantity
+ calculateTotalTaxAmount += (product.price.price - priceBeforeTax) * product.quantity
+ calculateTotalDiscountAmount += (product.price.price - product.price.priceDiscount) * product.quantity
+ }
+ setTotalPriceBeforeTax(calculateTotalPriceBeforeTax)
+ setTotalTaxAmount(calculateTotalTaxAmount)
+ setTotalDiscountAmount(calculateTotalDiscountAmount)
+ }, [products])
+
+ const updateQuantity = (value, productId, operation = '') => {
+ let productIndex = products.findIndex((product) => product.id == productId)
+ if (productIndex < 0) return
+
+ let productsToUpdate = products
+ let quantity = productsToUpdate[productIndex].quantity
+ if (value != '' && isNaN(parseInt(value))) return
+ value = value != '' ? parseInt(value) : ''
+ switch (operation) {
+ case 'PLUS':
+ quantity += value
+ break
+ case 'MINUS':
+ if ((quantity - value) < 1) return
+ quantity -= value
+ break
+ case 'BLUR':
+ if (value != '') return
+ quantity = 1
+ break
+ default:
+ quantity = value
+ break
+ }
+ productsToUpdate[productIndex].quantity = quantity
+ setProducts([ ...productsToUpdate ])
+ }
+
+ const toggleSelected = (productId) => {
+ let productIndex = products.findIndex((product) => product.id == productId)
+ if (productIndex < 0) return
+
+ let productsToUpdate = products
+ productsToUpdate[productIndex].selected = !productsToUpdate[productIndex].selected
+ setProducts([ ...productsToUpdate ])
+ }
+
+ const selectedProduct = () => {
+ if (!products) return []
+ return products.filter((product) => product.selected == true)
+ }
return (
- <div className="p-4">
- <div className="flex justify-between mb-4">
+ <div className="pt-6">
+ <div className="flex justify-between mb-4 px-4">
<h1 className="font-semibold">Daftar Produk Belanja</h1>
<Link href="/">Cari Produk Lain</Link>
</div>
- <div className="flex flex-col gap-y-4">
- { cart.data?.map((product) => (
+ <div className="flex flex-col gap-y-4 px-4">
+ { products?.map((product) => (
<div key={product.id} className="flex">
- <div className="w-4/12">
- <Image src={product?.parent?.image} alt={product?.name} className="object-contain object-center border border-gray_r-6 h-32 w-full rounded-md" />
- </div>
- <div className="flex-1 px-2">
- <div>{ product?.parent?.name }</div>
+ <button
+ type="button"
+ className="flex items-center mr-2"
+ onClick={() => toggleSelected(product.id)}
+ >
+ { !product.selected && (
+ <div className="w-5 h-5 border border-gray_r-11 rounded" />
+ ) }
+ { product.selected && (
+ <CheckIcon className="border bg-red_r-10 w-5 text-white" />
+ ) }
+ </button>
+ <Link
+ href={createSlug('/shop/product/', product.parent.name, product.parent.id)}
+ className="w-3/12 flex-shrink-0"
+ >
+ <Image src={product?.parent?.image} alt={product?.name} className="object-contain object-center border border-gray_r-6 h-40 w-full rounded-md" />
+ </Link>
+ <div className="flex-1 px-2 text-caption-1">
+ <Link
+ href={createSlug('/shop/product/', product.parent.name, product.parent.id)}
+ className="line-clamp-2 leading-6 !text-gray_r-12 font-normal"
+ >
+ { product?.parent?.name }
+ </Link>
+ <div className="text-gray_r-11 mt-1">{ product.code }</div>
+ { product?.price?.discountPercentage > 0 && (
+ <div className="flex gap-x-1 items-center mt-3">
+ <div className="text-gray_r-11 line-through text-caption-2">
+ {currencyFormat(product?.price?.price)}
+ </div>
+ <div className="badge-solid-red">
+ {product?.price?.discountPercentage}%
+ </div>
+ </div>
+ ) }
+ <div className="font-normal mt-1">
+ { currencyFormat(product?.price?.priceDiscount) }
+ </div>
+ <div className="flex justify-between items-center mt-1">
+ <div className="text-red_r-11 font-medium">
+ { currencyFormat(product?.price?.priceDiscount * product.quantity) }
+ </div>
+ <div className="flex gap-x-2">
+ <button
+ type="button"
+ className="btn-light px-2 py-1"
+ onClick={() => updateQuantity(1, product.id, 'MINUS')}
+ >
+ -
+ </button>
+ <input
+ className="form-input w-10 border-0 border-b rounded-none py-1 px-0 text-center"
+ value={product.quantity}
+ onChange={(e) => updateQuantity(e.target.value, product.id)}
+ onBlur={(e) => updateQuantity(e.target.value, product.id, 'BLUR')}
+ />
+ <button
+ type="button"
+ className="btn-light px-2 py-1"
+ onClick={() => updateQuantity(1, product.id, 'PLUS')}
+ >
+ +
+ </button>
+ </div>
+ </div>
</div>
</div>
)) }
</div>
+ <div className="sticky bottom-0 left-0 w-full p-4 mt-6 border-t border-gray_r-6 bg-white">
+ <div className="flex justify-between mb-4">
+ <div className="text-gray_r-11">
+ Total: <span className="text-red_r-11 font-semibold">{ currencyFormat(totalPriceBeforeTax - totalDiscountAmount + totalTaxAmount) }</span>
+ </div>
+ </div>
+ <div className="flex gap-x-3">
+ <button
+ type="button"
+ className="btn-yellow flex-1"
+ disabled={selectedProduct().length == 0}
+ onClick={() => router.push('/shop/quotation')}
+ >
+ Quotation
+ </button>
+ <button
+ type="button"
+ className="btn-solid-red flex-1"
+ disabled={selectedProduct().length == 0}
+ onClick={() => router.push('/shop/checkout')}
+ >
+ Checkout
+ </button>
+ </div>
+ </div>
</div>
)
}
diff --git a/src/lib/cart/hooks/useCart.js b/src/lib/cart/hooks/useCart.js
index 44931b8a..9eb01e74 100644
--- a/src/lib/cart/hooks/useCart.js
+++ b/src/lib/cart/hooks/useCart.js
@@ -3,11 +3,11 @@ import { useQuery } from "react-query"
import _ from "lodash"
import CartApi from "../api/CartApi"
-const useCart = () => {
+const useCart = ({ enabled }) => {
const cart = getCart()
const variantIds = _.keys(cart).join(',')
const fetchCart = async () => CartApi({ variantIds })
- const { data, isLoading } = useQuery('cart', fetchCart)
+ const { data, isLoading } = useQuery('cart', fetchCart, { enabled })
return {
cart: { data, isLoading }
diff --git a/src/lib/product/components/Product.jsx b/src/lib/product/components/Product.jsx
index 396eba5f..39d29d4d 100644
--- a/src/lib/product/components/Product.jsx
+++ b/src/lib/product/components/Product.jsx
@@ -8,7 +8,7 @@ import Select from "react-select"
import ProductSimilar from "./ProductSimilar"
import LazyLoad from "react-lazy-load"
import { toast } from "react-hot-toast"
-import { addItemCart } from "@/core/utils/cart"
+import { updateItemCart } from "@/core/utils/cart"
const informationTabOptions = [
{ value: 'specification', label: 'Spesifikasi' },
@@ -75,7 +75,7 @@ const Product = ({ product }) => {
toast.error('Jumlah barang minimal 1')
return
}
- addItemCart({
+ updateItemCart({
productId: activeVariant.id,
quantity
})
@@ -98,7 +98,7 @@ const Product = ({ product }) => {
{ activeVariant?.price?.discountPercentage > 0 && (
<div className="flex gap-x-1 items-center mt-2">
<div className="text-gray_r-11 line-through text-caption-1">
- {currencyFormat(activeVariant?.price?.priceDiscount)}
+ {currencyFormat(activeVariant?.price?.price)}
</div>
<Badge type="solid-red">
{activeVariant?.price?.discountPercentage}%
@@ -106,7 +106,7 @@ const Product = ({ product }) => {
</div>
) }
<h3 className="text-red_r-11 font-semibold mt-1">
- { activeVariant?.price?.price > 0 ? currencyFormat(activeVariant?.price?.price) : (
+ { activeVariant?.price?.priceDiscount > 0 ? currencyFormat(activeVariant?.price?.priceDiscount) : (
<span className="text-gray_r-11 leading-6 font-normal">
Hubungi kami untuk dapatkan harga terbaik,&nbsp;
<a href="https://wa.me/" className="text-red_r-11 underline">klik disini</a>