summaryrefslogtreecommitdiff
path: root/src-migrate/modules/cart/components
diff options
context:
space:
mode:
Diffstat (limited to 'src-migrate/modules/cart/components')
-rw-r--r--src-migrate/modules/cart/components/CartDetail.tsx76
-rw-r--r--src-migrate/modules/cart/components/CartItemAction.tsx104
-rw-r--r--src-migrate/modules/cart/components/CartItemSelect.tsx45
3 files changed, 225 insertions, 0 deletions
diff --git a/src-migrate/modules/cart/components/CartDetail.tsx b/src-migrate/modules/cart/components/CartDetail.tsx
new file mode 100644
index 00000000..734c61d3
--- /dev/null
+++ b/src-migrate/modules/cart/components/CartDetail.tsx
@@ -0,0 +1,76 @@
+import React, { useEffect, useMemo } from 'react'
+import { getAuth } from '~/common/libs/auth'
+import { useCartStore } from '../stores/useCartStore'
+import CartItem from '../ui/CartItem'
+import style from '../styles/CartDetail.module.css'
+import CartSummary from '../ui/CartSummary'
+import { Button, Tooltip } from '@chakra-ui/react'
+
+const CartDetail = () => {
+ const auth = getAuth()
+
+ const { loadCart, cart, summary } = useCartStore()
+
+ useEffect(() => {
+ if (typeof auth === 'object' && !cart) loadCart(auth.id)
+ }, [auth, loadCart, cart])
+
+ const hasSelectedPromo = useMemo(() => {
+ if (!cart) return false
+ for (const item of cart.products) {
+ if (item.cart_type === 'promotion' && item.selected) return true
+ }
+ return false
+ }, [cart])
+
+ const hasSelected = useMemo(() => {
+ if (!cart) return false
+ for (const item of cart.products) {
+ if (item.selected) return true
+ }
+ return false
+ }, [cart])
+
+ return (
+ <div className={style.wrapper}>
+ <div className='w-full md:w-3/4'>
+ {/* <div className='border border-gray-300 rounded-lg p-4 md:p-6'> */}
+ <div className=''>
+ <div className='text-h-lg font-semibold mb-6'>Keranjang Belanja</div>
+ <div className='grid grid-cols-1 gap-y-4'>
+ {!cart && <CartItem.Skeleton count={5} height='120px' />}
+ </div>
+ <div className='flex flex-col gap-y-8 border-t border-gray-300 pt-8'>
+ {cart?.products.map((item) => <CartItem key={item.id} item={item} />)}
+ </div>
+ </div>
+ </div>
+
+ <div className='w-full md:w-1/4 pl-6'>
+ <div className='border border-gray-300 p-4 rounded-md sticky top-[180px]'>
+ <CartSummary {...summary} isLoaded={!!cart} />
+ <div className='grid grid-cols-2 gap-x-3 mt-6'>
+ <Tooltip label={hasSelectedPromo ? 'Barang promo tidak dapat dibuat quotation' : ''}>
+ <Button
+ colorScheme='yellow'
+ w='full'
+ isDisabled={hasSelectedPromo || !hasSelected}>
+ Quotation
+ </Button>
+ </Tooltip>
+ <Tooltip label={hasSelected ? '' : 'Tidak ada item yang dipilih'}>
+ <Button
+ colorScheme='red'
+ w='full'
+ isDisabled={!hasSelected}>
+ Checkout
+ </Button>
+ </Tooltip>
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default CartDetail \ No newline at end of file
diff --git a/src-migrate/modules/cart/components/CartItemAction.tsx b/src-migrate/modules/cart/components/CartItemAction.tsx
new file mode 100644
index 00000000..742d1a39
--- /dev/null
+++ b/src-migrate/modules/cart/components/CartItemAction.tsx
@@ -0,0 +1,104 @@
+import React, { useEffect, useState } from 'react'
+
+import { Spinner, Tooltip } from '@chakra-ui/react'
+import { MinusIcon, PlusIcon, Trash2Icon } from 'lucide-react'
+
+import { CartItem } from '~/common/types/cart'
+import { getAuth } from '~/common/libs/auth'
+import { deleteUserCart, upsertUserCart } from '~/services/cart'
+
+import { useDebounce } from 'usehooks-ts'
+import { useCartStore } from '../stores/useCartStore'
+
+import style from '../styles/CartItemAction.module.css'
+
+type Props = {
+ item: CartItem
+}
+
+const CartItemAction = ({ item }: Props) => {
+ const auth = getAuth()
+
+ const [isLoadDelete, setIsLoadDelete] = useState<boolean>(false)
+ const [isLoadQuantity, setIsLoadQuantity] = useState<boolean>(false)
+
+ const [quantity, setQuantity] = useState<number>(item.quantity)
+
+ const { loadCart } = useCartStore()
+
+ const limitQty = item.limit_qty?.transaction || 0
+
+ const handleDelete = async () => {
+ if (typeof auth !== 'object') return
+
+ setIsLoadDelete(true)
+ await deleteUserCart(auth.id, [item.cart_id])
+ await loadCart(auth.id)
+ setIsLoadDelete(false)
+ }
+
+ const decreaseQty = () => { setQuantity((quantity) => quantity -= 1) }
+ const increaseQty = () => { setQuantity((quantity) => quantity += 1) }
+ const debounceQty = useDebounce(quantity, 1000)
+ useEffect(() => {
+ if (isNaN(debounceQty)) setQuantity(1)
+ if (limitQty > 0 && debounceQty > limitQty) setQuantity(limitQty)
+ }, [debounceQty, limitQty])
+
+ useEffect(() => {
+ const updateCart = async () => {
+ if (typeof auth !== 'object' || isNaN(debounceQty)) return
+
+ setIsLoadQuantity(true)
+ await upsertUserCart(auth.id, item.cart_type, item.id, debounceQty, item.selected)
+ await loadCart(auth.id)
+ setIsLoadQuantity(false)
+ }
+ updateCart()
+ //eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [debounceQty])
+
+ return (
+ <div className={style.actionSection}>
+ <button className={style.deleteButton} onClick={handleDelete} disabled={isLoadDelete}>
+ {isLoadDelete && <Spinner size='xs' />}
+ {!isLoadDelete && <Trash2Icon size={16} />}
+ </button>
+
+ <div className={style.quantitySection}>
+ {isLoadQuantity && (
+ <div className={style.quantityLoading}>
+ <Spinner size='sm' />
+ </div>
+ )}
+
+ <button
+ className={style.quantityControl}
+ onClick={decreaseQty}
+ disabled={quantity <= 1}
+ >
+ <MinusIcon size={16} />
+ </button>
+
+ <input
+ type='number'
+ className={style.quantity.toString()}
+ onChange={(e) => setQuantity(parseInt(e.target.value))}
+ value={quantity}
+ />
+
+ <Tooltip label={limitQty > 0 ? `Max. ${limitQty}` : ''}>
+ <button
+ className={style.quantityControl}
+ onClick={increaseQty}
+ disabled={limitQty > 0 && quantity >= limitQty}
+ >
+ <PlusIcon size={16} />
+ </button>
+ </Tooltip>
+ </div>
+ </div>
+ )
+}
+
+export default CartItemAction \ No newline at end of file
diff --git a/src-migrate/modules/cart/components/CartItemSelect.tsx b/src-migrate/modules/cart/components/CartItemSelect.tsx
new file mode 100644
index 00000000..f44b0d7e
--- /dev/null
+++ b/src-migrate/modules/cart/components/CartItemSelect.tsx
@@ -0,0 +1,45 @@
+import { Checkbox, Spinner } from '@chakra-ui/react'
+import React, { useState } from 'react'
+import { getAuth } from '~/common/libs/auth'
+import { CartItem } from '~/common/types/cart'
+import { upsertUserCart } from '~/services/cart'
+import { useCartStore } from '../stores/useCartStore'
+
+type Props = {
+ item: CartItem
+}
+
+const CartItemSelect = ({ item }: Props) => {
+ const auth = getAuth()
+ const { loadCart } = useCartStore()
+
+ const [isLoad, setIsLoad] = useState<boolean>(false)
+
+ const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
+ if (typeof auth !== 'object') return
+
+ setIsLoad(true)
+ await upsertUserCart(auth.id, item.cart_type, item.id, item.quantity, e.target.checked)
+ await loadCart(auth.id)
+ setIsLoad(false)
+ }
+
+ return (
+ <div className='w-5 my-auto'>
+ {isLoad && (
+ <Spinner className='my-auto' size='sm' />
+ )}
+ {!isLoad && (
+ <Checkbox
+ borderColor='gray.600'
+ colorScheme='red'
+ size='lg'
+ isChecked={item.selected}
+ onChange={handleChange}
+ />
+ )}
+ </div>
+ )
+}
+
+export default CartItemSelect \ No newline at end of file