diff options
Diffstat (limited to 'src-migrate/modules/cart')
16 files changed, 264 insertions, 195 deletions
diff --git a/src-migrate/modules/cart/components/CartDetail.tsx b/src-migrate/modules/cart/components/Detail.tsx index 734c61d3..c9de086b 100644 --- a/src-migrate/modules/cart/components/CartDetail.tsx +++ b/src-migrate/modules/cart/components/Detail.tsx @@ -1,10 +1,14 @@ +import style from '../styles/detail.module.css' + import React, { useEffect, useMemo } from 'react' +import Link from 'next/link' +import { Button, Tooltip } from '@chakra-ui/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' + +import CartItem from './Item' +import CartSummary from './Summary' const CartDetail = () => { const auth = getAuth() @@ -46,7 +50,7 @@ const CartDetail = () => { </div> </div> - <div className='w-full md:w-1/4 pl-6'> + <div className='w-full md:w-1/4 md:pl-6 mt-6 md:mt-0'> <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'> @@ -54,7 +58,8 @@ const CartDetail = () => { <Button colorScheme='yellow' w='full' - isDisabled={hasSelectedPromo || !hasSelected}> + isDisabled={hasSelectedPromo || !hasSelected} + > Quotation </Button> </Tooltip> @@ -62,7 +67,10 @@ const CartDetail = () => { <Button colorScheme='red' w='full' - isDisabled={!hasSelected}> + isDisabled={!hasSelected} + as={Link} + href='/shop/checkout' + > Checkout </Button> </Tooltip> diff --git a/src-migrate/modules/cart/components/Item.tsx b/src-migrate/modules/cart/components/Item.tsx new file mode 100644 index 00000000..92beda86 --- /dev/null +++ b/src-migrate/modules/cart/components/Item.tsx @@ -0,0 +1,109 @@ +import style from '../styles/item.module.css' + +import Image from 'next/image' +import React from 'react' +import { Skeleton, SkeletonProps, Tooltip } from '@chakra-ui/react' + +import formatCurrency from '~/common/libs/formatCurrency' +import { CartItem as CartItemProps } from '~/common/types/cart' + +import CartItemPromo from './ItemPromo' +import CartItemAction from './ItemAction' +import CartItemSelect from './ItemSelect' +import { PROMO_CATEGORY } from '~/constants/promotion' +import { InfoIcon } from 'lucide-react' + +type Props = { + item: CartItemProps + editable?: boolean +} + +const CartItem = ({ item, editable = true }: Props) => { + const image = item?.image || item?.parent?.image + + return ( + <div className={style.wrapper}> + {item.cart_type === 'promotion' && ( + <div className={style.header}> + {item.promotion_type?.value && ( + <Tooltip label={PROMO_CATEGORY[item.promotion_type?.value].description} placement="top" bgColor='red.600' p={2} rounded={6}> + <div className={style.badgeType}> + Paket {PROMO_CATEGORY[item.promotion_type?.value].alias} + <InfoIcon size={14} /> + </div> + </Tooltip> + )} + <div className='w-2' /> + <div> + Selamat! Pembelian anda lebih hemat {' '} + <span className={style.savingAmt}> + Rp {formatCurrency((item.package_price || 0) - item.subtotal)} + </span> + </div> + </div> + )} + + <div className={style.mainProdWrapper}> + {editable && <CartItemSelect item={item} />} + <div className='w-4' /> + <div className={style.image}> + {image && <Image src={image} alt={item.name} width={128} height={128} />} + {!image && <div className={style.noImage}>No Image</div>} + </div> + + <div className={style.details}> + <div className={style.name}>{item.name}</div> + <div className='mt-2 flex justify-between w-full'> + <div className='flex flex-col gap-y-1'> + {item.cart_type === 'promotion' && ( + <div className={style.discPriceSection}> + <span className={style.priceBefore}> + Rp {formatCurrency((item.package_price || 0))} + </span> + <span className={style.price}> + Rp {formatCurrency(item.subtotal)} + </span> + </div> + )} + + {item.cart_type === 'product' && ( + <> + <div className={style.price}> + Rp {formatCurrency(item.price.price)} + </div> + <div>{item.code}</div> + </> + )} + + <div> + {item.weight} Kg + </div> + </div> + + {editable && <CartItemAction item={item} />} + {!editable && <div className={style.quantity}>{item.quantity}</div>} + </div> + </div> + + </div> + + <div className="flex flex-col"> + {item.products?.map((product) => <CartItemPromo key={product.id} product={product} />)} + {item.free_products?.map((product) => <CartItemPromo key={product.id} product={product} />)} + </div> + </div> + ) +} + +CartItem.Skeleton = function CartItemSkeleton(props: SkeletonProps & { count: number }) { + return Array.from({ length: props.count }).map((_, index) => ( + <Skeleton key={index} + height='100px' + width='100%' + rounded='md' + {...props} + /> + )) +} + +export default CartItem
\ No newline at end of file diff --git a/src-migrate/modules/cart/components/CartItemAction.tsx b/src-migrate/modules/cart/components/ItemAction.tsx index 742d1a39..3e264aef 100644 --- a/src-migrate/modules/cart/components/CartItemAction.tsx +++ b/src-migrate/modules/cart/components/ItemAction.tsx @@ -1,3 +1,5 @@ +import style from '../styles/item-action.module.css' + import React, { useEffect, useState } from 'react' import { Spinner, Tooltip } from '@chakra-ui/react' @@ -10,7 +12,6 @@ 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 diff --git a/src-migrate/modules/cart/components/ItemPromo.tsx b/src-migrate/modules/cart/components/ItemPromo.tsx new file mode 100644 index 00000000..951d4d6a --- /dev/null +++ b/src-migrate/modules/cart/components/ItemPromo.tsx @@ -0,0 +1,41 @@ +import style from '../styles/item-promo.module.css' + +import Image from 'next/image' +import React from 'react' + +import { CartProduct } from '~/common/types/cart' + + +type Props = { + product: CartProduct +} + +const CartItemPromo = ({ product }: Props) => { + return ( + <div key={product.id} className={style.wrapper}> + <div className={style.imageWrapper}> + {product?.image && <Image src={product.image} alt={product.name} width={128} height={128} className={style.image} />} + </div> + + <div className={style.details}> + <div className={style.name}>{product.display_name}</div> + <div className='flex'> + <div className="flex flex-col"> + <div className={style.code}>{product.code}</div> + <div> + <span className={style.weightLabel}>Berat Barang: </span> + <span>{product.package_weight} Kg</span> + </div> + </div> + + <div className={style.quantity}> + {product.qty} + </div> + </div> + </div> + + </div> + ) +} + +export default CartItemPromo
\ No newline at end of file diff --git a/src-migrate/modules/cart/components/CartItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx index f44b0d7e..96e7c713 100644 --- a/src-migrate/modules/cart/components/CartItemSelect.tsx +++ b/src-migrate/modules/cart/components/ItemSelect.tsx @@ -1,8 +1,10 @@ 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 = { diff --git a/src-migrate/modules/cart/ui/CartSummary.tsx b/src-migrate/modules/cart/components/Summary.tsx index 390c1c77..a835bca9 100644 --- a/src-migrate/modules/cart/ui/CartSummary.tsx +++ b/src-migrate/modules/cart/components/Summary.tsx @@ -1,5 +1,6 @@ +import style from '../styles/summary.module.css' + import React from 'react' -import style from '../styles/CartSummary.module.css' import formatCurrency from '~/common/libs/formatCurrency' import clsxm from '~/common/libs/clsxm' import { Skeleton } from '@chakra-ui/react' diff --git a/src-migrate/modules/cart/stores/useCartStore.ts b/src-migrate/modules/cart/stores/useCartStore.ts index 1963df53..d3eaadb7 100644 --- a/src-migrate/modules/cart/stores/useCartStore.ts +++ b/src-migrate/modules/cart/stores/useCartStore.ts @@ -1,6 +1,6 @@ import { create } from 'zustand'; import { CartProps } from '~/common/types/cart'; -import { deleteUserCart, getUserCart, upsertUserCart } from '~/services/cart'; +import { getUserCart } from '~/services/cart'; type State = { cart: CartProps | null; @@ -56,7 +56,7 @@ const computeSummary = (cart: CartProps) => { discount += price - item.price.price_discount * item.quantity; } let total = subtotal - discount; - let tax = total * 0.11; + let tax = Math.round(total * 0.11); let grandTotal = total + tax; return { subtotal, discount, total, tax, grandTotal }; diff --git a/src-migrate/modules/cart/styles/CartItem.module.css b/src-migrate/modules/cart/styles/CartItem.module.css deleted file mode 100644 index 8ee3d3e9..00000000 --- a/src-migrate/modules/cart/styles/CartItem.module.css +++ /dev/null @@ -1,47 +0,0 @@ -.wrapper { - @apply border-b border-gray-300 pb-8; -} - -.mainProdWrapper { - @apply flex; -} - -.image { - @apply h-32 w-32 rounded flex p-2 border border-gray-300; -} - -.noImage { - @apply m-auto font-semibold text-gray-400; -} - -.details { - @apply ml-4 flex flex-col gap-y-1; -} - -.name { - @apply font-medium; -} - -.spacing2 { - @apply h-2; -} - -.discPriceSection { - @apply flex gap-x-2.5; -} - -.priceBefore { - @apply line-through text-gray-500; -} - -.price { - @apply text-red-600 font-medium; -} - -.savingAmt { - @apply text-success-600; -} - -.weightLabel { - @apply text-gray-500; -} diff --git a/src-migrate/modules/cart/styles/ProductPromo.module.css b/src-migrate/modules/cart/styles/ProductPromo.module.css deleted file mode 100644 index 3f6e7a05..00000000 --- a/src-migrate/modules/cart/styles/ProductPromo.module.css +++ /dev/null @@ -1,24 +0,0 @@ -.wrapper { - @apply ml-16 mt-4 flex; -} - -.imageWrapper { - @apply h-24 w-24 border border-gray-300 rounded p-2.5; -} - -.details { - @apply ml-4 flex flex-col gap-y-1; -} - -.name { - @apply font-medium; -} - -.code, -.weightLabel { - @apply text-gray-600; -} - -.quantity { - @apply py-2.5 bg-gray-100 border border-gray-300 h-fit my-auto rounded-md ml-auto font-medium w-12 text-center; -} diff --git a/src-migrate/modules/cart/styles/CartDetail.module.css b/src-migrate/modules/cart/styles/detail.module.css index 42d492bb..42d492bb 100644 --- a/src-migrate/modules/cart/styles/CartDetail.module.css +++ b/src-migrate/modules/cart/styles/detail.module.css diff --git a/src-migrate/modules/cart/styles/CartItemAction.module.css b/src-migrate/modules/cart/styles/item-action.module.css index e4db7fa5..e4db7fa5 100644 --- a/src-migrate/modules/cart/styles/CartItemAction.module.css +++ b/src-migrate/modules/cart/styles/item-action.module.css diff --git a/src-migrate/modules/cart/styles/item-promo.module.css b/src-migrate/modules/cart/styles/item-promo.module.css new file mode 100644 index 00000000..17dbf1c7 --- /dev/null +++ b/src-migrate/modules/cart/styles/item-promo.module.css @@ -0,0 +1,31 @@ +.wrapper { + @apply md:ml-16 ml-12 mt-4 flex; +} + +.imageWrapper { + @apply md:h-24 md:w-24 md:min-w-[96px] + h-20 w-20 min-w-[80px] + border border-gray-300 rounded + p-2.5; +} + +.image { + @apply w-full h-full object-contain; +} + +.details { + @apply ml-4 flex flex-col gap-y-1; +} + +.name { + @apply font-medium; +} + +.code, +.weightLabel { + @apply text-gray-600; +} + +.quantity { + @apply w-12 min-w-[48px] py-2.5 bg-gray-100 border border-gray-300 h-fit my-auto rounded-md ml-auto font-medium text-center; +} diff --git a/src-migrate/modules/cart/styles/item.module.css b/src-migrate/modules/cart/styles/item.module.css new file mode 100644 index 00000000..6380cdad --- /dev/null +++ b/src-migrate/modules/cart/styles/item.module.css @@ -0,0 +1,60 @@ +.wrapper { + @apply border-b border-gray-300 pb-8; +} + +.header { + @apply mb-4 flex items-center text-caption-1 leading-6; +} + +.badgeType { + @apply min-w-fit p-2 flex gap-x-1.5 rounded-md border border-danger-500 text-danger-500; +} + +.mainProdWrapper { + @apply flex; +} + +.image { + @apply md:h-32 md:w-32 md:min-w-[128px] + w-24 h-24 min-w-[96px] rounded flex p-2 border border-gray-300; +} + +.noImage { + @apply m-auto font-semibold text-gray-400; +} + +.details { + @apply ml-4 flex flex-col gap-y-1 w-full; +} + +.name { + @apply font-medium; +} + +.spacing2 { + @apply h-2; +} + +.discPriceSection { + @apply flex flex-col md:flex-row gap-x-2.5; +} + +.priceBefore { + @apply line-through text-gray-500; +} + +.price { + @apply text-red-600 font-medium; +} + +.savingAmt { + @apply text-success-600; +} + +.weightLabel { + @apply text-gray-500; +} + +.quantity { + @apply py-2.5 bg-red-100 border border-red-300 text-red-800 h-fit my-auto rounded-md ml-auto font-medium w-12 text-center; +} diff --git a/src-migrate/modules/cart/styles/CartSummary.module.css b/src-migrate/modules/cart/styles/summary.module.css index 48ccec28..48ccec28 100644 --- a/src-migrate/modules/cart/styles/CartSummary.module.css +++ b/src-migrate/modules/cart/styles/summary.module.css diff --git a/src-migrate/modules/cart/ui/CartItem.tsx b/src-migrate/modules/cart/ui/CartItem.tsx deleted file mode 100644 index 70d50bff..00000000 --- a/src-migrate/modules/cart/ui/CartItem.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import Image from 'next/image' -import React from 'react' -import formatCurrency from '~/common/libs/formatCurrency' -import { CartItem as CartItemProps } from '~/common/types/cart' -import ProductPromo from './ProductPromo' -import { Skeleton, SkeletonProps } from '@chakra-ui/react' -import style from '../styles/CartItem.module.css' -import CartItemAction from '../components/CartItemAction' -import CartItemSelect from '../components/CartItemSelect' - -type Props = { - item: CartItemProps -} - -const CartItem = ({ item }: Props) => { - const image = item?.image || item?.parent?.image - - return ( - <div className={style.wrapper}> - <div className={style.mainProdWrapper}> - <CartItemSelect item={item} /> - <div className='w-4' /> - <div className={style.image}> - {image && <Image src={image} alt={item.name} width={128} height={128} />} - {!image && <div className={style.noImage}>No Image</div>} - </div> - - <div className={style.details}> - <div className={style.name}>{item.name}</div> - <div className={style.spacing2} /> - {item.cart_type === 'promotion' && ( - <div className={style.discPriceSection}> - <span className={style.priceBefore}> - Rp {formatCurrency((item.package_price || 0))} - </span> - <span className={style.savingAmt}> - Hemat Rp {formatCurrency((item.package_price || 0) - item.subtotal)} - </span> - <span className={style.price}> - Rp {formatCurrency(item.subtotal)} - </span> - </div> - )} - {item.cart_type === 'product' && ( - <> - <div className={style.price}> - Rp {formatCurrency(item.price.price)} - </div> - <div>{item.code}</div> - </> - )} - <div> - <span className={style.weightLabel}>Berat barang: </span> - {item.weight} Kg - </div> - </div> - - <CartItemAction item={item} /> - </div> - - <div className="flex flex-col"> - {item.products?.map((product) => <ProductPromo key={product.id} product={product} />)} - {item.free_products?.map((product) => <ProductPromo key={product.id} product={product} />)} - </div> - </div> - ) -} - -CartItem.Skeleton = function CartItemSkeleton(props: SkeletonProps & { count: number }) { - return Array.from({ length: props.count }).map((_, index) => ( - <Skeleton key={index} - height='100px' - width='100%' - rounded='md' - {...props} - /> - )) -} - -export default CartItem
\ No newline at end of file diff --git a/src-migrate/modules/cart/ui/ProductPromo.tsx b/src-migrate/modules/cart/ui/ProductPromo.tsx deleted file mode 100644 index a41afc97..00000000 --- a/src-migrate/modules/cart/ui/ProductPromo.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Image from 'next/image' -import React from 'react' -import { CartProduct } from '~/common/types/cart' -import style from '../styles/ProductPromo.module.css' - -type Props = { - product: CartProduct -} - -const ProductPromo = ({ product }: Props) => { - return ( - <div key={product.id} className={style.wrapper}> - <div className={style.imageWrapper}> - {product?.image && <Image src={product.image} alt={product.name} width={128} height={128} />} - </div> - - <div className={style.details}> - <div className={style.name}>{product.display_name}</div> - <div className={style.code}>{product.code}</div> - <div> - <span className={style.weightLabel}>Berat Barang: </span> - <span>{product.package_weight} Kg</span> - </div> - </div> - - <div className={style.quantity}> - {product.qty} - </div> - </div> - ) -} - -export default ProductPromo
\ No newline at end of file |
